具有接口类型约束的C#泛型方法

时间:2013-01-29 09:59:12

标签: c# generics interface

我们假设我有:

  • 通用方法Get<T>
  • 一些接口IEntityIValue
  • 分别实现这些接口的几个类ex:Entity - &gt; IEntityValue - &gt; IValue等。

=&GT;有没有办法让Get<T>方法只允许接口作为泛型类型?

Get<IEntity>(42); //Allowed
Get<Entity>(42);  //Compiler error

我目前的解决方案如下:

  • 具有类型约束Get<T>的通用方法where T: IPersistable(以防止大多数类型作为参数传递)
  • 接口实现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");
}

=&GT;问题是:

  1. 它不干净......我可以忍受,因为
  2. 只能检查很少的类型
  3. 签名与函数的确无关。它允许IPersistable进入,但不是真的&lt; - 真的让我感到困惑:(
  4. 编辑:我正在考虑这样的限制,以避免我的班级人口过剩。

    我在那个类中有类似8或9个泛型方法的东西,它们都以这种方式工作。直观的做法是@DanielHilgarth建议每种类型只有1种方法。目前可以使用4种或5种类型调用这些方法。但是,这仍然意味着该课程中有32-40种方法。

    如果可能,我想避免这种情况。

    Edit2 :防止“真实”类被调用的需要来自协方差/逆变问题。 EntityDao和ValueDao Get<T>方法返回IEntityIValue个对象。当我在GetAll<T>方法中调用集合时,当我查询单个对象时,什么工作正常,因为我无法在IEnumerable<IValue>中强制转换IEnumerable<Value>

    我刚从@JonSkeets注意到关于列表的转换this answer。这可能是一种解决方法......

2 个答案:

答案 0 :(得分:5)

您应该只创建专用方法。带有if的示例代码显示您当前的方法不做一件事。它有多个。

请继续:

GetEntity(42);
GetValue(13);

public IEntity GetEntity(long id)
{
    return EntityDao.Get(id);
}

public IValue GetValue(long id)
{
    return ValueDao.Get(id);
}

在所有图层上都更加清晰:

  1. GetEntityGet<IEntity>
  2. 你清楚地传达了可能的信息。您没有任何运行时异常。
  3. 您的get方法不需要任何类型切换。
  4. 如果这会导致您的服务上有太多类似的方法,那么就应该打破新的类,例如一个用于Entity,另一个用于Value。 然后,您可以提供返回新类的服务属性。这与我在实施my query objects时所做的相同。它可能如下所示:service.Values.Get(13)service.Entities.Get(42)

答案 1 :(得分:1)

这可能是另一种选择:

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);
}