在 C# 4.0 中,为啥方法中的 out 参数不能是协变的?
Posted
技术标签:
【中文标题】在 C# 4.0 中,为啥方法中的 out 参数不能是协变的?【英文标题】:In C# 4.0 why can't an out parameter in a method be covariant?在 C# 4.0 中,为什么方法中的 out 参数不能是协变的? 【发布时间】:2010-10-06 09:06:14 【问题描述】:鉴于这个神奇的界面:
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”方法参数为不变类型。是否有明确的理由为什么不允许这样做,或者是否有可能在未来的版本中解决?
【问题讨论】:
【参考方案1】:有趣。但是,在 CLI 级别没有“out”之类的东西——只有“ref”;有一个属性可以帮助编译器(用于明确赋值),它说“你不需要传递它”。
也许这个限制是因为 CLI 没有“out”,只有“ref”。
【讨论】:
对于信息,我发现多个博客等都说相同,但没有一个 cmets 来自“官方”MS 来源。不过,我非常确信它是正确的……C# 4.0 的差异仍然基于 CLI 规则。【参考方案2】:虽然有点麻烦,但您可以使用协方差包装器:
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));
【讨论】:
以上是关于在 C# 4.0 中,为啥方法中的 out 参数不能是协变的?的主要内容,如果未能解决你的问题,请参考以下文章
为啥在面向 .NET Standard 的项目中可以不分配 Out 参数?
C#和Java中的构造器constructor是啥?起啥作用?为啥不可以被override??