2012-07-23 12 views
5

Sto cercando di creare una classe generica:T non contiene la definizione per 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(); 
    } 
} 

In questo codice che sto errore che ottengo:

T non contiene la definizione per RowKey

ma i parametri che sostituiranno il T in fase di esecuzione hanno la definizione di RowKey. Forse perché il compilatore non sta ottenendo la definizione per RowKey in T in fase di compilazione, è per questo che sto ottenendo questo errore. Qualcuno può dirmi come risolvere questo problema?

+0

Come commento - ho upvoted una delle risposte corrette: il compilatore non interessa quello che T sarà tardi. Si preoccupa di ciò che CONOSCE in fase di compilazione, il che significa che è possibile creare ClassName e Dumbo non ha RowKey -> errore. Aggiungi un vincolo;) – TomTom

+0

Pro illustra il punto di TomTom: in C# è possibile scrivere un tipo * in fase di esecuzione * e richiamare il tipo generico per il nuovo tipo, purché soddisfi il vincolo, funzionerà. Questo è molto diverso dai modelli C++. –

risposta

11

Per fare che si avrebbe bisogno di un vincolo di interfaccia:

interface IHazRowKey { 
    string RowKey { get; } 
} 

E specificare questa restrizione:

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

E specificare : IHazRowKey su ciascuna delle implementazioni:

public class Foo : IHazRowKey {....} 

Il esistente membro RowKey dovrebbe corrispondere (assumendo i t è una proprietà, non un campo), quindi non è necessario aggiungere altro codice aggiuntivo. Se si tratta in realtà di un campo (che non dovrebbe essere, IMO) poi:

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

Non dovrebbe essere ICanHazRowKey? :) –

+0

grazie per la risposta, ma la classe che sto implementando come una classe generica è derivata dall'altra classe, mi dispiace di non aver menzionato questo in questione. Significa che è qualcosa del tipo: public class ClassName : Base –

+2

@Tom che non cambia nulla; è consentito l'ereditarietà di più interfacce e l'ereditarietà di una singola classe, –

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

è necessario definire constraint per risolvere questo:

public interface IHasRowKey 
{ 
    string RowKey {get;} 
} 

public class classname<T> where T : IHasRowKey 
{ 

} 
8

C'è una grande differenza tra i modelli C++ e C# generici: non importa quali classi si passa per istanziare il generico, se il il compilatore non conosce un metodo su T al momento della compilazione della tua classe o metodo generico, ti darebbe un errore. Questo perché C# ha bisogno di una capacità di compilare il codice generico separatamente dalle sue posizioni di istanziazione (ricorda, non ci sono intestazioni in C#).

È possibile definire un'interfaccia e limitare T ad esso per utilizzare proprietà e metodi all'interno di un generico. Aggiungi RowKey all'interfaccia e aggiungi where T : myinterface alla dichiarazione generica.

0

Il mio caso non è possibile utilizzare un'interfaccia per contenere RowKey, perche 'ho due classi che hanno diverse proprietà e metodi. Non posso semplicemente unirli e mettere queste proprietà e questi metodi in un'interfaccia o una classe wrapper, perché perde l'obiettivo di usare una classe generica. La mia soluzione sta usando la riflessione con la classe generica. Es .:

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

Ecco il riferimento alla classe PropertyInfo http://msdn.microsoft.com/en-us/library/System.Reflection.PropertyInfo_methods(v=vs.110).aspx

Problemi correlati