可变的值类型包装器,传递给迭代器
我正在编写一个需要传递可变整数的迭代器。
public IEnumerable Foo(ref int valueThatMeansSomething) { // Stuff yield return ...; }
这让我知道“错误476迭代器不能有ref或out参数”。
我需要的是在迭代器中修改这个整数值,并由迭代器的调用者使用。 换句话说,无论上面的调用Foo()
想要知道valueThatMeansSomething
和Foo()
的结束值都可以使用它本身。 真的,我想要一个引用类型的整数,而不是值类型。
我唯一能想到的是写一个封装了我的整数的类,允许我修改它。
public class ValueWrapper where T : struct { public ValueWrapper(T item) { this.Item = item; } public T Item { get; set; } }
所以:
ValueWrapper w = new ValueWrapper(0); foreach(T item in Foo(w)) { // Do stuff } if (w.Item < 0) { /* Do stuff */ }
BCL中是否有任何类或机制来处理这个问题? 上面提出的ValueWrapper
任何缺陷?
(我的实际使用比上面的例子更复杂,因此处理调用Foo()
foreach
循环中的变量不是一个选项。期间。)
不,我非常有信心BCL中没有任何东西可以做到这一点。 你最好的选择正是你提出的我想的。 ValueWrapper
的实现确实不需要比你提出的更复杂。
当然,它不能保证是线程安全的,但如果你需要,你可以简单地将自动属性转换为带有支持变量的标准属性,并将该字段标记为volatile
(以确保该值是最新的一直)。
如果您只需要写入值,那么另一种技术将是:
public IEnumerable Foo(Action setter) { ... } int value = 0; foreach(var x in Foo(x => {value=x;}) { ... }
巧合的是,我将在7月份的博客中对迭代器块有如此多的愚蠢限制的原因进行系列研究。 “为什么没有参考参数?” 将在系列的早期。
http://blogs.msdn.com/ericlippert/archive/tags/Iterators/default.aspx
我一直认为BCL真的应该有一个类和接口类似如下:
public delegate void ActByRef(ref T1 p1); public delegate void ActByRefRef (ref T1 p1,ref T2 p2); 公共接口IReadWriteActUpon { T值{得; 组;} void ActUpon(ActByRef proc); void ActUpon (ActByRefRef proc, ref TExtraparam ExtraParam); } public sealed class MutableWrapper :IReadWrite { 公共T值; public MutableWrapper(T value){this.Value = value; } T IReadWriteActUpon .Value {get {return this.Value;} set {this.Value = value;}} public void ActUpon(ActByRef proc) { proc(ref Value); } public void ActUpon (ActByRefRef proc, ref TExtraparam ExtraParam) { proc(ref Value,ref ExtraParam); } }
尽管许多人本能地将字段包装在自动属性中,但字段通常允许更清晰,更有效的代码,尤其是在使用值类型时。 在许多情况下,通过使用属性可以获得的增加的封装在高效和语义上可能是值得的,但是当类型的整个目的是要完全暴露和可变的状态的类对象时,这种封装是适得其反的。
包含该接口不是因为MutableWrapper
许多用户想要使用该接口,而是因为IReadWriteActUpon
在各种情况下都有用,其中一些需要封装,有人MutableWrapper
一个实例可能希望将其传递给代码,该代码旨在处理封装在IReadWriteActUpon
接口中的数据。