3

假设我有:

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

=> 有没有办法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");
}

=> 问题是:

  1. 它不干净......我可以忍受,因为只有很少的类型可供检查
  2. 签名与函数的实际作用不匹配。它允许输入IPersistable,但不是真的 <-这真的让我很烦:(

编辑:我正在考虑这样的限制,以避免我的班级人数过多。

我在那个类中有 8 或 9 个通用方法,它们几乎都以这种方式工作。直观的做法是@DanielHilgarth 建议每种类型只有一种方法。目前只能用 4 或 5 种类型调用方法。但是,这仍然意味着该类中有 32-40 个方法。

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

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

我刚刚注意到@JonSkeets 关于列表投射的这个答案。这可能是一种解决方法...

4

2 回答 2

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. GetEntity对比Get<IEntity>
  2. 你清楚地传达什么是可能的。您没有任何运行时异常。
  3. 您的 get 方法不需要任何类型切换。

如果这会导致您的服务上有太多类似的方法,那么是时候打破新的类了,例如一个 forEntity和一个 for Value。然后,您可以提供返回新类的服务属性。这与我在实现查询对象时所做的相同。然后它可能看起来像这样:service.Values.Get(13)service.Entities.Get(42)

于 2013-01-29T10:02:51.567 回答
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);
}
于 2013-01-29T12:16:19.210 回答