문제

나는 변한 정수를 전달 해야하는 반복자를 쓰고 있습니다.

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

    yield return ...;
}

이 Nets Me "오류 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; }
}

그래서:

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

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

BCL에서 이미 처리 할 수있는 클래스 나 메커니즘이 있습니까? 모든 결함 ValueWrapper<T> 위에 제안 되었습니까?

(실제 사용은 위의 예보다 더 복잡하므로 내부의 변수를 처리합니다. foreach 호출하는 루프 Foo() 옵션이 아닙니다. 기간.)

도움이 되었습니까?

해결책

아니, 나는 이것을 할 수있는 BCL에 존재하는 것이 없다고 확신한다. 최선의 선택은 정확히 당신이 제안한 것입니다. 의 구현 ValueWrapper 실제로 제안한 것보다 더 복잡 할 필요는 없습니다.

물론, 그것은 스레드-안전한 것으로 보장되지는 않지만, 필요한 경우 자동 속성을 백업 변수를 가진 표준 속성으로 변환하고 필드를 다음과 같이 표시 할 수 있습니다. volatile (값을 항상 최신 상태로 유지하려면).

다른 팁

값만 쓸 필요가 있다면 다른 기술은 다음과 같습니다.

public IEnumerable<whatever> Foo(Action<int> 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<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> 상호 작용.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top