반복자로 전달할 수있는 값 유형의 변이 가능한 래퍼
-
20-08-2019 - |
문제
나는 변한 정수를 전달 해야하는 반복자를 쓰고 있습니다.
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>
상호 작용.