可变的值类型包装器,传递给迭代器

Col*_*ett 5 c# iterator value-type reference-type .net-3.5

我正在编写一个需要传递可变整数的迭代器.

public IEnumerable<T> Foo(ref int valueThatMeansSomething)
{
    // Stuff

    yield return ...;
}
Run Code Online (Sandbox Code Playgroud)

这让我知道"错误476迭代器不能有ref或out参数".

我需要的是在迭代器中修改这个整数值,并由迭代器的调用者使用.换句话说,无论Foo()上述任何调用都想知道最终值,valueThatMeansSomething并且Foo()可以自己使用它.真的,我想要一个引用类型的整数,而不是值类型.

我唯一能想到的是写一个封装了我的整数的类,并允许我修改它.

public class ValueWrapper<T>
    where T : struct
{
    public ValueWrapper(T item)
    {
        this.Item = item;
    }

    public T Item { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

所以:

ValueWrapper<int> w = new ValueWrapper<int>(0);
foreach(T item in Foo(w))
{
    // Do stuff
}

if (w.Item < 0) { /* Do stuff */ }
Run Code Online (Sandbox Code Playgroud)

在BCL中是否有任何类或机制来处理这个问题?ValueWrapper<T>上面提出的任何缺陷?

(我的实际使用比上面的例子更复杂,所以在我的foreach循环中处理调用的变量Foo()不是一个选项.期间.)

Eri*_*ert 5

如果您只需要写入值,那么另一种技术将是:

public IEnumerable<whatever> Foo(Action<int> setter) { ... }

int value = 0;
foreach(var x in Foo(x => {value=x;}) { ... }
Run Code Online (Sandbox Code Playgroud)

巧合的是,我将在7月份对我的博客中对迭代器块进行如此多的愚蠢限制的原因进行系列研究."为什么没有参考参数?" 将在系列的早期.

http://blogs.msdn.com/ericlippert/archive/tags/Iterators/default.aspx


Nol*_*rin 4

不,我非常有信心 BCL 中没有任何东西可以做到这一点。我认为你最好的选择正是你所提出的。实施ValueWrapper实际上不需要比您提出的更复杂。

当然,它不能保证是线程安全的,但如果您需要,您可以简单地将自动属性转换为带有支持变量的标准属性,并将该字段标记为volatile(以确保该值是最新的)次)。

  • 使字段变为易失性不足以确保线程安全,因为 C# 规范不能保证对任意值类型的写入是原子的。易失性不保证原子性,它只是消除了一些编译器优化引起的排序问题。 (2认同)