如何表示泛型IHandler<T>的超类型,以声明通用处理程序集合?
问题解答
问题翻译
给定泛型类型IHandler<T>,如何表示它的超类型,以便声明一个List<T2>(其中T2可以是任意IHandler<T>)?
请注意:本问题并非针对列表,列表代码仅为示例需求构造。问题核心涉及开放泛型,方差概念同样适用于此,标题未提及列表。
示例代码(修正后):
public class NotGeneric { private readonly List</* 此处需替换为目标超类型 */> _handlers = new(); public void AddHandler(IHandler<object> handler) // 此处参数需匹配超类型 { _handlers.Add(handler); } }
解决方案
方案1:定义非泛型基接口(最通用)
给IHandler<T>定义一个非泛型的基接口IHandler,让所有泛型实现都继承这个基接口,这样就能用非泛型接口作为列表的元素类型,兼容任意IHandler<T>实例。
步骤如下:
- 声明非泛型基接口:
public interface IHandler { // 可在此定义所有Handler共有的非泛型方法/属性 } public interface IHandler<T> : IHandler { void Handle(T message); // 其他泛型成员 }
- 修改
NotGeneric类:
public class NotGeneric { private readonly List<IHandler> _handlers = new(); public void AddHandler(IHandler handler) { _handlers.Add(handler); } }
这种方式不受泛型方差限制,不管T是引用类型还是值类型,所有IHandler<T>实例都能存入列表。
方案2:利用泛型协变(仅适用于引用类型T)
如果IHandler<T>的泛型参数是输出型(即仅作为方法返回值,不作为参数),可以将接口标记为协变(使用out关键字),此时可以用IHandler<object>作为超类型(仅支持引用类型的T)。
步骤如下:
- 声明协变接口:
public interface IHandler<out T> { T GetResult(); // 注意:协变接口中T不能作为方法参数类型 }
- 修改
NotGeneric类:
public class NotGeneric { private readonly List<IHandler<object>> _handlers = new(); public void AddHandler(IHandler<object> handler) { _handlers.Add(handler); } }
此时,任意引用类型的IHandler<SomeReferenceType>都能隐式转换为IHandler<object>并存入列表,但值类型(如int、DateTime)的IHandler<T>无法转换,因为.NET不支持值类型的泛型协变。
注意事项
- 如果需要兼容所有类型的
T(包括值类型),优先选择方案1的非泛型基接口方式。 - 协变方案仅适用于
T为引用类型,且接口仅将T作为输出的场景。
内容的提问来源于stack exchange,提问作者Peter Wone
相关产品推荐
相关产品推荐

