C#泛型如何从ICollection推导类型避免重复指定类型参数
结论
C# 的泛型类型推导规则不支持从where T : ICollection<R>这类泛型约束反向推导未显式声明的泛型参数,因此你原有双泛型参数签名的方法,无法直接实现只传入List<User>一个泛型参数的调用效果。你可以通过修改方法签名的方式实现目标调用体验,以下是两种常用可行方案:
方案1:重载方法,拆分不同使用场景的签名
这是兼容性最好、开发成本最低的方案,支持所有主流.NET版本:
第一步:新增默认返回List<R>的重载,90%场景下可以完全省略泛型参数声明
// 常用场景默认返回List<R>,泛型参数可直接从serializeItem委托推导,无需显式声明 public static List<R> ReadCollection<R>(this BinaryReader reader, Func<BinaryReader, R> serializeItem) { // 复用你原有ReadCollection的核心逻辑即可 return reader.ReadCollection<List<R>, R>(serializeItem); }
第二步:保留自定义集合类型的重载,通过工厂委托推导类型
// 针对需要自定义集合类型的场景,通过传入集合工厂委托推导泛型参数,无需显式声明 public static TCollection ReadCollection<TCollection, R>(this BinaryReader reader, Func<TCollection> collectionFactory, Func<BinaryReader, R> serializeItem) where TCollection : ICollection<R>, new() { var collection = collectionFactory(); int count = reader.ReadInt32(); // 你的原有读取逻辑,比如先读集合长度 for (int i = 0; i < count; i++) { collection.Add(serializeItem(reader)); } return collection; }
调用效果
// 普通返回List<User>的场景,完全不用写泛型参数 var users = _reader.ReadCollection(reader => new User { Id = reader.ReadInt32(), Name = reader.ReadString() }); // 需要自定义集合类型的场景,也无需显式声明泛型参数 var userSet = _reader.ReadCollection(() => new HashSet<User>(), reader => new User { Id = reader.ReadInt32(), Name = reader.ReadString() });
方案2:封装特定集合类型的快捷扩展方法
如果你常用的集合类型只有少数几种,可以直接封装对应的快捷方法,完全避免泛型参数声明:
public static List<R> ReadList<R>(this BinaryReader reader, Func<BinaryReader, R> serializeItem) { return reader.ReadCollection<List<R>, R>(serializeItem); } public static HashSet<R> ReadHashSet<R>(this BinaryReader reader, Func<BinaryReader, R> serializeItem) { return reader.ReadCollection<HashSet<R>, R>(serializeItem); }
调用时直接使用对应方法即可:
var users = _reader.ReadList(reader => new User { Id = reader.ReadInt32(), Name = reader.ReadString() });
内容的提问来源于stack exchange,提问作者Horno
相关产品推荐
相关产品推荐

