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; } }
我尝试两种写法均出现错误:
- 直接向
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>”
- 已存在
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
相关产品推荐
相关产品推荐

