鉴于这种神奇接口:

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));
    }
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top