使用List <T>创建一个允许T的子类的接口

时间:2019-06-03 14:10:19

标签: c# generics interface

我得到了ContainerAContainerBElementAElementB类。除了可以添加接口之外,由于原因很好我无法修改这些类。

我想要的是类似IElements的界面(期望合法),因为它可以让我轻松地遍历元素并从ContainerA或{{1}的元素中读取属性而不知道实际使用了哪个具体实现。在任何类上都没有方法。对于元素类,我只需要访问ContainerB实现的属性,例如ElementA属性。

我有什么选择?

Id

我希望达到类似的目的

public interface IElements
{
    List<ElementA> Elements { get; set; }
}

public class ContainerA : IElements
{
    public List<ElementA> Elements { get; set; }
}

public class ContainerB : IElements
{
    public List<ElementB> Elements { get; set; }
}

public class ElementA
{
    public string Id { get; set; }    
}

public class ElementB : ElementA
{
}

2 个答案:

答案 0 :(得分:1)

有很多方法可以切成薄片,但是我会考虑在此处使用具有约束的泛型。我还将考虑元素对象的接口(或抽象基类),例如:

public interface IElement
{
    int Id { get; set; }
}

您的通用元素界面将如下所示:

public interface IElements<TElement>
    where TElement : ElementA
{
    List<TElement> Elements { get; set; }
}

使容器类看起来像这样:

public class ContainerA : IElements<ElementA>
{
    public List<ElementA> Elements { get; set; }
}

public class ContainerB : IElements<ElementB>
{
    public List<ElementB> Elements { get; set; }
}

现在,您可以访问实现您的接口的任何对象的Id属性,例如:

public void DoFoo<TElement>(IElements<TElement> elements)
    where TElement : ElementA
{
    foreach (var element in elements.Elements)
    {
        // This will compile fine
        var id = element.Id;
    }
}

答案 1 :(得分:1)

IEnumerablecovariant,即IEnumerable<SubtypeOfT>IEnumerable<T>的子类型。因此,以下应该起作用:

public interface IElements
{
    IEnumerable<ElementA> ReadOnlyElements { get; }
}

public class ContainerA : IElements
{
    public List<ElementA> Elements { get; set; }
    IEnumerable<ElementA> IElements.ReadOnlyElements => Elements;
}

public class ContainerB : IElements
{
    public List<ElementB> Elements { get; set; }
    IEnumerable<ElementA> IElements.ReadOnlyElements => Elements;
}

您可以按以下步骤遍历它们:

IElements container = ...;
foreach (var element in container.ReadOnlyElements)
{
    Console.WriteLine(element.Id);
}