2016-09-25 108 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); 
    } 
} 

爲方便起見,我將它放在一個非泛型的同名名稱上。