【问题标题】:Why do I need to explicitly define the generic argument's generic type on a generic class?为什么我需要在泛型类上显式定义泛型参数的泛型类型?
【发布时间】:2016-09-26 04:04:52
【问题描述】:

考虑以下场景:

public interface IEntity<TKey>
{
    TKey { get; set; }
}

public interface IRepository<TEntity, TKey>
      where TEntity : IEntity<TKey>
{
    void Store(TEntity entity);
    void Delete(TKey key);
}

为什么我需要明确地将TKey 作为通用参数添加到IRepository

编译器不能从TEntity的类型推断或推断它吗?

我想实现这样的目标:

public interface IRepository<TEntity>
    where TEntity : IEntity<TKey>
{
     void Store(TEntity entity);
     void Delete(TKey key);
}

TKey 并不是只在运行时才知道:

IRepository<User> userRepo = new ConcreteRepository<User>();

User 在哪里实现IEntity&lt;string&gt;

【问题讨论】:

  • 编译器遵循规范。该规范需要类型参数,并且可以说这样做是有充分理由的,因为它避免了歧义和额外/复杂的规则:考虑IEnumerableIEnumerable&lt;T&gt;,它们都是单独的类型。问题的结尾令人困惑,因为 TKey 是赋予类型域限制的名称,与“运行时”..
  • 编译器能否推断它并不重要——它不能推断,仅此而已。这很烦人,是的,但事实就是这样。 CLR 规范要求定义每个泛型类型参数。 F# 的类型推断比 C# 好得多,而且它仍然必须这样做(主要区别在于,当您调用只采用 TEntity 的方法时,它会推断出正确的类型 :)。

标签: c# .net generics


【解决方案1】:

在你的例子中:

public interface IRepository<TEntity>
where TEntity : IEntity<TKey> {
   void Store(TEntity entity);
   void Delete(TKey key);
}

TKey 是未定义的类型参数。你可以说where TEntity : IEntity&lt;string&gt;,因为string 是一个已定义的类型。但如果要使用类型参数,则需要先定义它。

请注意,编译器不知道这里的TKey 是什么。它是一种类型吗?是泛型类型参数吗?

你也许可以做这样的事情,但它不会再被强输入TEntity。这可能会或可能不会被接受:

public interface IRepository<TKey> {
   void Store(IEntity<TKey> entity);
   void Delete(TKey key);
}

【讨论】:

    【解决方案2】:

    因为 C# 规范要求构造函数参数。关于这个问题的规范答案在这里Why can't the C# constructor infer type?

    值得注意的是:我们几乎在 C#6 中得到了它。您可以通过使用简单地调用构造函数的静态方法来解决它。比如

    public class Entity<TKey>
    {
        public Entity(TKey k)
        {
    
        }
    
    }
    
    public static class Entity
    {
        public static Entity<MyKey> Create<MyKey>(MyKey mk)
        {
            return new Entity<MyKey>(mk);
        }
    }
    

    为了方便起见,我将它放在同名的非泛型类型上。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多