【问题标题】:Casting from concrete Type to interface从具体类型到接口的铸造
【发布时间】:2021-08-27 07:17:18
【问题描述】:

我有以下无法编译的代码

using System.Collections.Generic;

public interface IElement
{
}

public class AElement : IElement
{
    public void DoSomethingSpecial()
    { }
}

public class Container<TElement>
{
    public List<TElement> Elements { get; } = new();
}



public class Program
{
    public static Container<IElement> GetContainer()
    {
        var concreteContainer = new Container<AElement>();
        concreteContainer.Elements.ForEach(e => e.DoSomethingSpecial());
        
        return concreteContainer; // Cannot implicitly convert type 'Container<AElement>' to 'Container<IElement>'
    }
    
    public static void Main()
    {
        var myContainer = GetContainer();
    }
}

我阅读了有关协方差、不变性、逆变性和输出类型的文档。 而且我比一开始更困惑。

有什么办法解决这个问题?

在线代码:https://dotnetfiddle.net/85AgfT

【问题讨论】:

  • AElement "is-a" IElement。但这不会使Container&lt;AElement&gt; "is-a" Container&lt;IElement&gt;。他们没有这样的关系。
  • 对于为什么会发生这种情况,请参阅this。一旦你理解了这一点,你可能需要重新考虑你想做什么。
  • @Sweeper:回答“不要这样”也可以。但是,有人想要一个接口但在内部你必须使用具体类型(首先),这不是很常见吗?因为每个具体的实现都需要自定义行为?
  • @Klamsi 这并不矛盾。如果你有一个列表,比如说List&lt;IElement&gt;,其中IElementMethodA(),你可以将任何具体的类添加到实现该接口的列表中。其中任何一个都可以有自己的MethodA() 实现。所以,调用foreach( var item in list ) item.MethodA();会执行相应的实现。
  • 我会向后倾斜并重新考虑我的概念。

标签: c# generics interface


【解决方案1】:

需要生成隐式转换运算符:

public class Container<IElement>
{
    public List<IElement> Elements { get; } = new List<IElement>();

    public static implicit operator Container<IElement>(Container<AElement> v)
    {
        //here you need to create Container<IElement> with your Container<AElement> 'v' values
        return new Container<IElement>();
    }
}

【讨论】:

  • 哦,不。实际上这个容器是一个更大的层次结构。我希望有一个班轮;)
  • @Klamsi 不,不是这样。我什至认为你需要回到黑板上来完成你的设计...... :(
【解决方案2】:

终于搞定了

using System.Collections.Generic;

public interface IContainer<out TElement>
{
}

public interface IElement
{
}

public class AElement : IElement
{
    public void DoSomethingSpecial()
    { }
}

public class Container<TElement> : IContainer<TElement>
{
    public List<TElement> Elements { get; } = new();
}



public class Program
{
    public static IContainer<IElement> GetContainer()
    {
        var concreteContainer = new Container<AElement>();
        concreteContainer.Elements.ForEach(e => e.DoSomethingSpecial());
        
        return concreteContainer;
    }
    
    public static void Main()
    {
        var myContainer = GetContainer();
    }
}

使Container 也成为一个接口并使用一个输出类型参数

【讨论】:

    猜你喜欢
    • 2021-05-20
    • 1970-01-01
    • 1970-01-01
    • 2015-01-03
    • 2012-12-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-04
    • 1970-01-01
    相关资源
    最近更新 更多