[英]In C# 4.0 why can't an out parameter in a method be covariant?
鉴于这个神奇的界面:
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编译器在接口定义中给出了错误 - 它要求'out'方法参数为不变类型。 是否有一个强硬的原因,为什么不允许这样做,或者是否可以在未来版本中解决这个问题?
有趣。 但是,在CLI级别没有“out”这样的东西 - 只有“ref”; 有一个属性可以帮助编译器(对于明确的赋值)说“你不需要传入它”。
也许这个限制是因为CLI没有“out”,只有“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));
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.