具有接口类型约束的 C# 泛型方法
Posted
技术标签:
【中文标题】具有接口类型约束的 C# 泛型方法【英文标题】:C# generic method with interface type constraint 【发布时间】:2013-01-29 09:59:12 【问题描述】:假设我有:
通用方法Get<T>
几个接口IEntity
,IValue
分别实现这些接口的几个类,例如:Entity
-> IEntity
、Value
-> IValue
等。
=> Get<T>
方法有没有办法只允许接口作为泛型类型?
Get<IEntity>(42); //Allowed
Get<Entity>(42); //Compiler error
我当前的解决方案如下所示:
具有类型约束where T: IPersistable
的泛型方法Get<T>
(以防止大多数类型作为参数传递)
接口实现IPersistable
函数主动检查类型:
public T Get<T>(long id) where T : IPersistable
if (typeof (T) == typeof (IEntity))
return (T) EntityDao.Get(id);
if (typeof (T) == typeof (IValue))
return (T) ValueDao.Get(id);
//...
throw new TechnicalException("Type not supported");
=> 问题是:
-
它不干净......我可以忍受,因为只有很少的类型可供检查
签名与函数实际所做的不匹配。它允许
IPersistable
进入,但不是真的这真的让我很烦:(
编辑:我正在考虑这样的限制以避免我的班级人数过多。
我在那个类中有 8 或 9 个通用方法,它们几乎都以这种方式工作。直观的做法是@DanielHilgarth 建议每种类型只有一种方法。目前只能用 4 或 5 种类型调用方法。但是,这仍然意味着该类中有 32-40 个方法。
如果可能的话,我想避免这种情况。
Edit2:防止调用“真实”类的需求来自协变/逆变问题。 EntityDao 和 ValueDao Get<T>
方法返回 IEntity
和 IValue
对象。当我在 GetAll<T>
方法中调用集合时,当我查询单个对象失败时,什么工作正常,因为我无法在 IEnumerable<Value>
中转换 IEnumerable<IValue>
。
我刚刚注意到来自@JonSkeets 的this answer 关于列表的转换。这可能是一种解决方法...
【问题讨论】:
能否解释一下,为什么需要这样的约束? 当然,我刚刚编辑了问题。 这是一个解释,你为什么要创建泛型方法而不是工厂方法的数量。如果你解释一下为什么这个方法应该只受接口类型的限制,那将会很有帮助。 【参考方案1】:您应该只创建专用方法。带有if
的示例代码表明您当前的方法没有做任何事情。它有多个。
随你去吧:
GetEntity(42);
GetValue(13);
public IEntity GetEntity(long id)
return EntityDao.Get(id);
public IValue GetValue(long id)
return ValueDao.Get(id);
这在所有层上都更干净:
GetEntity
与 Get<IEntity>
您清楚地传达了可能的情况。您没有任何运行时异常。
您的 get 方法不需要任何类型切换。
如果这会导致你的服务上有太多类似的方法,那么是时候打破新的类了,例如一个用于Entity
,一个用于Value
。
然后,您可以提供返回新类的服务属性。这与我在实现my query objects 时所做的相同。然后它可能看起来像这样:service.Values.Get(13)
和 service.Entities.Get(42)
【讨论】:
我可以,但我担心课堂上的方法“过多”。我有类似 8 或 9 个通用方法,它们在该类中都以类似的方式工作。如果我分解我的泛型方法,我会得到大约 40 种方法。如果可能的话,我想避免这种情况。 @TimBourguignon:在这种情况下,您应该开设一些新课程。 这确实是一种可能性......我一直试图避免这种可能性,因为该服务中的单个入口点确实很方便(所有提到的方法都是吸气剂,所以在某种程度上它是有意义的它们都组合在一起)... 您可以提供返回新类的服务属性。这与我在实现my query objects 时所做的相同。它可能看起来像这样:service.Values.Get(13)
和 service.Entities.Get(42)
。
我不得不考虑一下,但这是个好主意,它看起来确实很性感:D【参考方案2】:
这可能是另一种选择:
abstract class Persistable<T>
protected static Func<long, T> mapFunction;
public static T Get(long id)
return mapFunction(id);
class Entity : Persistable<Entity>
public static Entity()
Persistable<Entity>.mapFunction = input => EntityDao.Get(input);
class Value : Persistable<Value>
public static Value()
Persistable<Value>.mapFunction = input => ValueDao.Get(input);
您的Get
方法将是这样的:
public T Get<T>(long id) // maybe you restrict the T to something
Persistable<T>.Get(id);
【讨论】:
以上是关于具有接口类型约束的 C# 泛型方法的主要内容,如果未能解决你的问题,请参考以下文章