2012-07-23 67 views
5

我想創建一個泛型類的定義:T不包含RowKey

public class ClassName<T> 
{ 
    public T AccessEntity(string id) 
    { 
     return (from e in ServiceContext.CreateQuery<T>(TableName) 
       where e.RowKey == id // error here! 
       select e).FirstOrDefault(); 
    } 
} 

在這段代碼中我得到錯誤:

T不包含RowKey定義

但在運行時將取代T的參數具有RowKey的定義。也許因爲編譯器在編譯時沒有得到T中RowKey的定義,這就是爲什麼我得到這個錯誤。任何人都可以告訴我如何解決這個問題?

+0

參考作爲註釋 - 我upvoted正確答案之一:編譯不在乎T將是什麼版本。它關心在編譯時它知道些什麼,這意味着你可以創建ClassName ,並且Dumbo沒有RowKey - >錯誤。 Adda約束;) – TomTom 2012-07-23 14:53:29

+0

Pro說明了TomTom的觀點:在c#中,你可以在運行時編寫一個*類型,並且調用新類型的泛型類型 - 只要滿足約束條件,它就可以工作。這與C++模板非常不同。 – 2012-07-23 15:08:27

回答

11

要做到這一點,你需要一個接口約束:

interface IHazRowKey { 
    string RowKey { get; } 
} 

,並指定此限制:

public class classname<T> where T : IHazRowKey {...} 

而且在每一個實現指定: IHazRowKey

public class Foo : IHazRowKey {....} 

的現有的RowKey會員應該匹配它(假設我t是一個屬性,而不是一個字段),所以你不需要添加任何其他額外的代碼。如果它實際上是一個字段(它不應該,IMO),則:

public class Foo : IHazRowKey { 
    string HazRowKey.RowKey { get { return this.RowKey; } } 
    ... 
} 
+3

不應該是ICanHazRowKey嗎? :) – 2012-07-23 14:53:25

+0

謝謝你的回答,但是我作爲一個泛型類實現的類已經從另一個類驅動出來,抱歉沒有提到這個問題。意思是這樣的:public class ClassName :Base – 2012-07-23 14:57:54

+2

@Tom不會改變任何東西;你被允許多接口繼承和單類繼承, – 2012-07-23 15:06:43

1
class YourClass // or extract an interface 
{ 
    public string RowKey { get; set; } 
} 

class YourGeneric<T> where T : YourClass 
{ 
    // now T is strongly-typed class containing the property requested 
} 
3

您需要定義constraint來解決這個問題:

public interface IHasRowKey 
{ 
    string RowKey {get;} 
} 

public class classname<T> where T : IHasRowKey 
{ 

} 
8

有C++模板和C#泛型之間的主要區別:不要緊,你通過什麼類來實例化通用的,如果編譯器在編譯泛型類或方法時不知道T上的方法,它會給你一個錯誤。這是因爲C#需要能夠將泛型代碼與實例化地點分開編譯(請記住,C#中沒有頭文件)。

您可以定義一個接口,並將其限制爲T以便在泛型中使用屬性和方法。將RowKey添加到您的界面,並將where T : myinterface添加到您的通用聲明中。

0

我的情況下不能使用界面包含RowKey,因爲我有一個有不同的屬性和方法兩大類。我不能將它們合併,並將這些屬性和方法放入一個包裝接口或類中,導致它失去了使用泛型類的目的。我的解決方案是使用Generic類的反射。例如: -

public class ClassName<T> { 
    private T _genericType; 
    public ClassName(T t) { 
     _genericType = t; 
    } 

    public void UseGenericType() { 
     // Code below allows you to get RowKey property from your generic 
     // class type param T, cause you can't directly call _genericType.RowKey 
     PropertyInfo rowKeyProp = _genericType.GetType().GetProperty("RowKey"); 
     if(rowKeyProp != null) { // if T has RowKey property, my case different T has different properties and methods 
      string rowKey = rowKeyProp.GetValue(_genericType).ToString(); 
      // Set RowKey property to new value 
      rowKeyProp.setValue(_genericType, "new row key"); 
     } 
    } 
} 

這裏是一個的PropertyInfo類http://msdn.microsoft.com/en-us/library/System.Reflection.PropertyInfo_methods(v=vs.110).aspx