在C#4.0中,为什么不能在一个方法的输出参数进行协变?
-
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);
}
我表明帽子可能是空的,用一个单独的布尔返回值(以前的版本或许会已返回一个空帽子空兔)。但我仍然只输出兔子,所以没有做任何事情到以前的版本不同逻辑。
在C#4.0编译在CTP给出了接口定义的错误 - 它需要“出”方法参数是一个不变的类型。有,为什么这是不允许的硬和快速的原因,或者是它的东西,可能会在未来版本中得到解决?
解决方案
有趣。然而,在CLI水平还有作为“走出去”没有这样的事 - 只有“参考”;有帮助的编译器(用于明确分配),说:“你不需要把它传递”的属性。
也许这种限制是由于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