2016-09-25 138 views
0

考虑以下情形:为什么我需要在泛型类中明确定义泛型参数的泛型类型?

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

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

为什么我需要expliclty添加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<string>

+0

编译器遵循一个规范。该规范要求类型参数,它可以这样做是出于很好的理由,因为它避免了含糊不清和额外/复杂的规则:考虑“IEnumerable”和“IEnumerable ”,它们都是独立的类型。问题的结尾是令人困惑的,因为TKey是赋予类型域限制的名称,与“运行时”分开。 – user2864740

+0

编译器是否可以推断它并不相关 - 它没有,这就是它。这很烦人,是的,但这就是它的方式。 CLR规范要求定义每个泛型类型参数。 F#比C#有更好的类型推断,它仍然必须这样做(主要区别在于,当你调用一个只需要'TEntity' :)的方法时,它会推断出正确的类型)。 – Luaan

回答

1

在您的例子:

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

TKey是一个未定义的类型参数。你可以说where TEntity : IEntity<string>,因为string是一个定义的类型。但是如果你打算使用类型参数,你需要先定义它。

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

您也许可以做类似的事情,但不会再在TEntity上输入强类型。这可能会也可能不会被接受:

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

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

值得注意的是一些事情:我们几乎在C#6中得到它。你可以通过使用一个简单地调用你的构造函数的Static方法来解决它。例如

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

为方便起见,我将它放在一个非泛型的同名名称上。