You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#:如何创建包含实现同一接口的不同泛型类的列表?

问题

我需要创建一个包含泛型类GenericClass<T>的列表,其中T为实现ISomeClass接口的不同类(ClassA、ClassB)。现有代码定义如下:

public class GenericClass<T>
    where T : ISomeClass
{
    public string PropA { get; set; }
    public List<T> ListClass { get; set; }
}

public interface ISomeClass
{
    public string PropInterface { get; set; }
}

public class ClassA : ISomeClass
{
    public string PropClassA { get; set; }
    public string PropInterface { get; set; }
}

public class ClassB : ISomeClass
{
    public string PropClassB { get; set; }
    public string PropInterface { get; set; }
}

我尝试两种写法均出现错误:

  1. 直接向List<GenericClass<ISomeClass>>中添加GenericClass<ClassA>实例:
var list = new List<GenericClass<ISomeClass>>();
list.Add(new GenericClass<ClassA> 
{
    PropA = "Prop Generic", 
    ListClass = new List<ClassA> 
    { 
        new ClassA { PropClassA = "Property A", PropInterface = "..." }
    } 
}); // 错误:无法将类型“GenericClass<ClassA>”转换为“GenericClass<ISomeClass>”
  1. 已存在List<ClassA>实例,将其赋值给GenericClass<ISomeClass>的ListClass属性:
var listA = new List<ClassA> { new ClassA { ... } };

var list = new List<GenericClass<ISomeClass>>();
list.Add(new GenericClass<ISomeClass> { ListClass = listA }); // 错误:无法隐式转换类型“System.Collections.Generic.List<ClassA>”为“System.Collections.Generic.List<ISomeClass>”

请问有什么方法可以实现该需求?

解决方案

方法1:利用泛型协变(定义协变接口)

泛型类默认不支持协变,你可以定义一个带out关键字的协变接口IGenericClass<out T>,让GenericClass<T>实现这个接口,这样就能把GenericClass<ClassA>隐式转换为IGenericClass<ISomeClass>:

// 定义协变接口,out关键字标记T为协变类型
public interface IGenericClass<out T> where T : ISomeClass
{
    string PropA { get; }
    // 协变接口不能包含输入型泛型成员(比如可写的List<T>),所以暴露只读的IEnumerable<T>
    // 因为IEnumerable<T>本身是协变的
    IEnumerable<T> ListClass { get; }
}

// 修改GenericClass实现协变接口
public class GenericClass<T> : IGenericClass<T>
    where T : ISomeClass
{
    public string PropA { get; set; }
    public List<T> ListClass { get; set; }

    // 显式实现接口的ListClass属性,返回IEnumerable<T>
    IEnumerable<T> IGenericClass<T>.ListClass => ListClass;
}

现在可以创建List<IGenericClass<ISomeClass>>并添加不同子类的实例:

var list = new List<IGenericClass<ISomeClass>>();
list.Add(new GenericClass<ClassA> 
{
    PropA = "Prop Generic", 
    ListClass = new List<ClassA> 
    { 
        new ClassA { PropClassA = "Property A", PropInterface = "..." }
    } 
});
list.Add(new GenericClass<ClassB> 
{
    PropA = "Another Prop", 
    ListClass = new List<ClassB> 
    { 
        new ClassB { PropClassB = "Property B", PropInterface = "..." }
    } 
});

方法2:转换子类列表为List<ISomeClass>

如果不需要保留GenericClass<T>的具体泛型类型,只是想存入List<GenericClass<ISomeClass>>,可以把List<ClassA>转换为List<ISomeClass>:

var listA = new List<ClassA> { new ClassA { PropClassA = "A", PropInterface = "..." } };
// 将List<ClassA>转换为List<ISomeClass>
var convertedList = listA.Cast<ISomeClass>().ToList();

var list = new List<GenericClass<ISomeClass>>();
list.Add(new GenericClass<ISomeClass> { PropA = "Test", ListClass = convertedList });

方法3:使用非泛型基类

定义一个非泛型的基类GenericClassBase,让GenericClass<T>继承它,然后用List<GenericClassBase>来存储所有实例:

public class GenericClassBase
{
    public string PropA { get; set; }
    // 定义非泛型方法获取列表,方便统一访问
    public virtual IEnumerable<ISomeClass> GetList() => Enumerable.Empty<ISomeClass>();
}

public class GenericClass<T> : GenericClassBase
    where T : ISomeClass
{
    public List<T> ListClass { get; set; }

    public override IEnumerable<ISomeClass> GetList() => ListClass;
}

使用示例:

var list = new List<GenericClassBase>();
list.Add(new GenericClass<ClassA> 
{
    PropA = "Prop Generic", 
    ListClass = new List<ClassA> { new ClassA { PropClassA = "A", PropInterface = "..." } }
});
list.Add(new GenericClass<ClassB> 
{
    PropA = "Another Prop", 
    ListClass = new List<ClassB> { new ClassB { PropClassB = "B", PropInterface = "..." } }
});

内容的提问来源于stack exchange,提问作者John Sari

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 12:50:21