2012-07-23 19 views
5

Estoy tratando de crear una clase genérica:T no contiene la definición para 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(); 
    } 
} 

En este código que estoy error que conseguía:

T no contiene la definición para rowKey

pero los parámetros que reemplazarán a T en tiempo de ejecución tienen la definición de RowKey. Tal vez porque el compilador no obtiene la definición de RowKey en T en el momento de la compilación, es por eso que recibo este error. ¿Alguien puede decirme cómo resolver este problema?

+0

Como comentario - Me upvoted una de las respuestas correctas: el compilador no le importa lo T será más tarde. Se preocupa por lo que SABE en el momento de la compilación, lo que significa que PUEDE crear ClassName y Dumbo no tiene RowKey -> error. Adda constraint;) – TomTom

+0

Pro ilustra el punto de TomTom: en C# se puede escribir un tipo * en tiempo de ejecución *, e invocar el tipo genérico para el nuevo tipo - siempre que cumpla con la restricción, funcionará. Esto es muy diferente a las plantillas de C++. –

Respuesta

11

para hacer eso se necesitaría una restricción de la interfaz:

interface IHazRowKey { 
    string RowKey { get; } 
} 

y especificar esta restricción:

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

y especificar : IHazRowKey en cada una de las implementaciones:

public class Foo : IHazRowKey {....} 

El el miembro existente RowKey debería coincidir con él (asumiendo que t es una propiedad, no un campo), por lo que no debería necesitar agregar ningún otro código adicional. Si en realidad es un campo (que no debe ser, OMI) a continuación:

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

¿No debería ser ICanHazRowKey? :) –

+0

gracias por la respuesta, pero la clase que estoy implementando como una clase genérica ha derivado de la otra clase, lo siento por no mencionar esto en cuestión. Significa que es algo así como: public class ClassName : Base –

+2

@Tom que no cambia nada; se le permite herencia de interfaz múltiple y herencia de clase única, –

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

es necesario definir constraint de resolver esto:

public interface IHasRowKey 
{ 
    string RowKey {get;} 
} 

public class classname<T> where T : IHasRowKey 
{ 

} 
8

Hay una gran diferencia entre las plantillas de C++ y C# genéricos: no importa lo que las clases se pasa a una instancia del genérico, si el el compilador no sabe acerca de un método en T en el momento de compilar su clase o método genérico, le daría un error. Esto se debe a que C# necesita una capacidad para compilar el código genérico por separado de sus lugares de creación de instancias (recuerde, no hay encabezados en C#).

Puede definir una interfaz y restringir T a ella para usar propiedades y métodos dentro de un genérico. Agregue RowKey a su interfaz, y agregue where T : myinterface a su declaración genérica.

0

Mi caso no puede utilizar una interfaz para contener rowKey, porque tengo dos clases que tienen diferentes propiedades y métodos. No puedo simplemente fusionarlos y poner estas propiedades y métodos en una interfaz o clase de contenedor, porque pierde el objetivo de usar clases genéricas. Mi solución es usar la reflexión con la clase Genérica. Ej .:

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

su referencia es a la clase PropertyInfo http://msdn.microsoft.com/en-us/library/System.Reflection.PropertyInfo_methods(v=vs.110).aspx

Cuestiones relacionadas