C# 4.0에서 왜 메소드의 Out 매개 변수가 공분산이 될 수 없습니까?
-
22-08-2019 - |
문제
이 마법의 인터페이스를 감안할 때 :
public interface IHat<out TRabbit>
{
TRabbit Take();
}
그리고이 클래스 계층 구조 :
public class Rabbit { }
public class WhiteRabbit : Rabbit { }
이제 이것을 컴파일 할 수 있습니다.
IHat<WhiteRabbit> hat1 = null;
IHat<Rabbit> hat2 = hat1;
그것은 훌륭합니다. 그러나 인터페이스를 다르게 정의하면 어떻게해야합니까?
public interface IHat<out TRabbit>
{
bool Take(out TRabbit r);
}
별도의 부울 리턴 값을 사용하여 모자가 비어있을 수 있음을 나타냅니다 (이전 버전은 아마도 빈 모자에서 널 토끼를 반환했을 것입니다). 그러나 나는 여전히 토끼 만 출력하고 있으므로 이전 버전과 논리적으로 다른 일을하지 않습니다.
CTP의 C# 4.0 컴파일러는 인터페이스 정의에서 오류를 제공합니다. 이것이 허용되지 않는 이유가 어려운 이유가 있습니까?
해결책
흥미로운. 그러나 CLI 수준에서는 "out" - "Ref"와 같은 것은 없습니다. 컴파일러 (명확한 할당의 경우)를 도와주는 속성이 있습니다.
어쩌면이 제한은 CLI에 "아웃"이없고 "Ref"만 가지고 있기 때문일 수 있습니다.
다른 팁
약간의 번거 로움이지만 공분산 래퍼를 사용할 수 있습니다.
public class CovariantListWrapper<TOut, TIn> : IList<TOut> where TIn : TOut
{
IList<TIn> list;
public CovariantListWrapper(IList<TIn> list)
{
this.list = list;
}
public int IndexOf(TOut item)
{
// (not covariant but permitted)
return item is TIn ? list.IndexOf((TIn)item) : -1;
}
public TOut this[int index]
{
get { return list[index]; }
set { throw new InvalidOperationException(); }
}
public bool Contains(TOut item)
{
// (not covariant but permitted)
return item is TIn && list.Contains((TIn)item);
}
public void CopyTo(TOut[] array, int arrayIndex)
{
foreach (TOut t in this)
array[arrayIndex++] = t;
}
public int Count { get { return list.Count; } }
public bool IsReadOnly { get { return true; } }
public IEnumerator<TOut> GetEnumerator()
{
foreach (TIn t in list)
yield return t;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Insert(int index, TOut item) { throw new InvalidOperationException(); }
public void RemoveAt(int index) { throw new InvalidOperationException(); }
public void Add(TOut item) { throw new InvalidOperationException(); }
public void Clear() { throw new InvalidOperationException(); }
public bool Remove(TOut item) { throw new InvalidOperationException(); }
}
이를 통해 원래 입력 된대로 컬렉션을 유지하고 분리 된 사본을 만들지 않고 공분산으로 참조 할 수 있으므로 원본에 대한 업데이트가 공변량 사용에서 볼 수 있습니다. 예시:
class CovarianceWrapperExample
{
class Person { }
class Employee : Person { }
void ProcessPeople(IList<Person> people) { /* ... */ }
void Foo()
{
List<Employee> employees = new List<Employee>();
// cannot do:
ProcessPeople(employees);
// can do:
ProcessPeople(new CovariantListWrapper<Person, Employee>(employees));
}
}
제휴하지 않습니다 StackOverflow