2009-06-26 15 views
5

変更可能な整数を渡す必要があるイテレータを作成しています。イテレータに渡す値型の変更可能なラッパー

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

    yield return ...; 
} 

これは私のネット "エラー476のイテレータは、refまたはoutパラメータを持つことができません"。

私が必要とするのは、この整数値がイテレータで変更され、イテレータの呼び出し側が使用できることです。言い換えれば、上記のFoo()の呼び出しがvalueThatMeansSomethingFoo()という最終値を知りたければ、それ自体を使用することができます。実際、値の型ではなく参照型の整数が必要です。

私が考えることができるのは、私の整数をカプセル化し、それを変更できるクラスを書くことだけです。

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

    public T Item { get; set; } 
} 

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

if (w.Item < 0) { /* Do stuff */ } 

BCLで、すでにこれを処理する任意のクラスやメカニズムはありますか?上記のValueWrapper<T>の瑕疵はありますか?

(私の実際の使用はそれほどオプションではありませんFoo()を呼び出して、私のforeachループ内の変数を扱う上記の例よりも複雑である。期間。)

答えて

4

いや、私は既存の何もないかなり確信していますこれを行うことができるBCL。あなたの最善の選択肢は、あなたが私が考えている提案とまったく同じです。 ValueWrapperの実装は、本当にあなたが提案したものよりも複雑である必要はありません。もちろん

、スレッドセーフであるとは限りませんですが、あなたは単にバッキング変数と標準の一つに自動プロパティを変換し、保証するために(volatileとしてフィールドをマークすることができていることが必要な場合は値がアップです常に最新のもの)。あなたが唯一の値を記述する必要がある場合は

+2

フィールドのvolatileは、任意の値型への書き込みがC#仕様でアトミックであることが保証されていないため、スレッドの安全性を保証するには不十分です。揮発性はアトミック性を保証するものではなく、単にコンパイラ最適化による順序付けの問題を取り除くだけです。 –

+0

スレッドの安全性が気になる場合は、ロックを使用してください。 –

+0

@エリック:うん、良い点。私はもともと原子性を保証していると書いていましたが、それはすぐに削除しました。 – Noldorin

5

その後、別の手法は次のようになります。偶然にも

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

int value = 0; 
foreach(var x in Foo(x => {value=x;}) { ... } 

、私は私のブログでイテレータブロックのように多くの間抜けな制約がある理由のシリーズをやっていますよ7月に。 "なぜrefパラメータはありませんか?"シリーズの早い段階にあるでしょう。

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

0

私は長いBCLは本当に、次のようなクラスやインタフェース何か持っているべきであると考えている:多くの人々は本能的に自動プロパティのフィールドをラップが

 
public delegate void ActByRef<T1,T2>(ref T1 p1); 
public delegate void ActByRefRef<T1,T2>(ref T1 p1, ref T2 p2); 
public interface IReadWriteActUpon<T> 
{ 
    T Value {get; set;} 
    void ActUpon(ActByRef<T> proc); 
    void ActUpon<TExtraParam>(ActByRefRef<T, TExtraParam> proc, 
          ref TExtraparam ExtraParam); 
} 

public sealed class MutableWrapper<T> : IReadWrite<T> 
{ 
    public T Value; 
    public MutableWrapper(T value) { this.Value = value; } 
    T IReadWriteActUpon<T>.Value {get {return this.Value;} set {this.Value = value;} } 
    public void ActUpon(ActByRef<T> proc) 
    { 
    proc(ref Value); 
    } 
    public void ActUpon<TExtraParam>(ActByRefRef<T, TExtraParam> proc, 
          ref TExtraparam ExtraParam) 
    { 
    proc(ref Value, ref ExtraParam); 
    } 
} 

を、フィールドには、多くの場合、クリーナー許可特に値型を使用する場合はより効率的なコードになります。多くの状況では、プロパティを使用して増加したカプセル化が効率的かつセマンティクス的にコストの価値があるかもしれませんが、型の目的全体が完全に公開され変更可能なクラスオブジェクトである場合、そのようなカプセル化は逆効果です。

インターフェースはMutableWrapper<T>の多くのユーザーが代わりにインターフェイスを使用したいので、いない含まれているのではなく、IReadWriteActUpon<T>は、さまざまな状況で有用であろうので、そのうちのいくつかは、カプセル化を伴うだろう、とインスタンスを持っている人MutableWrapper<T>のコードは、IReadWriteActUpon<T>インターフェイスでカプセル化されたデータを扱うように設計されたコードに渡すことができます。

関連する問題