2008-10-13 19 views
12

Estoy escribiendo un código para un constructor de clase que recorre todas las propiedades de la clase y llama a un método estático genérico que rellena mi clase con datos de una API externa. Así que tengo esto como una clase de ejemplo:Reflexión y tipos genéricos

public class MyClass{ 
    public string Property1 { get; set; } 
    public int Property2 { get; set; } 
    public bool Property3 { get; set; } 

    public static T DoStuff<T>(string name){ 
    // get the data for the property from the external API 
    // or if there's a problem return 'default(T)' 
    } 
} 

Ahora en mi constructor Quiero algo como esto:

public MyClass(){ 
    var properties = this.GetType().GetProperties(); 
    foreach(PropertyInfo p in properties){ 
    p.SetValue(this, DoStuff(p.Name), new object[0]); 
    } 
} 

así que el constructor anterior se produce un error porque no voy a suministrar la tipo genérico.

Entonces, ¿cómo paso en el tipo de la propiedad?

+0

En este momento la cuestión es un poco confuso, es que hay algunos errores tipográficos en el segundo código ¿retazo? – smaclell

+0

Sí, creo que quiso escribir "MyClass.DoStuff (p.Name)" como el segundo parámetro para p.SetValue(). –

+0

Sí, cometí un error en el segundo fragmento de código. –

Respuesta

19

¿Desea llamar a DoStuff <T> con T = el tipo de cada propiedad? En cuyo caso, "como es" que tendría que utilizar la reflexión y MakeGenericMethod - es decir,

var properties = this.GetType().GetProperties(); 
foreach (PropertyInfo p in properties) 
{ 
    object value = typeof(MyClass) 
    .GetMethod("DoStuff") 
    .MakeGenericMethod(p.PropertyType) 
    .Invoke(null, new object[] { p.Name }); 
    p.SetValue(this, value, null); 
} 

Sin embargo, esto no es muy bonita. En realidad, me pregunto si no sería mejor tener:

static object DoStuff(string name, Type propertyType); 
... and then 
object value = DoStuff(p.Name, p.PropertyType); 

¿Qué le dan los genéricos en este ejemplo? Tenga en cuenta que los tipos de valor seguirán encerrados, etc. durante la llamada de reflexión, e incluso en el boxeo isn't as bad as you might think.

Por último, en muchos escenarios, TypeDescriptor.GetProperties() es más apropiado que Type.GetProperties() - permite modelos de objetos flexibles, etc.

7

¿Su código de constructor significaba para leer como esto:

public MyClass(){ 
    var properties = this.GetType().GetProperties(); 
    foreach(PropertyInfo p in properties){ 
    p.SetValue(this, DoStuff(p.Name), new object[0]); 
    } 
} 

? Tenga en cuenta el DoStuff en lugar de MyClass.

Si es así, el problema es que está tratando de usar genéricos cuando en realidad no son aplicables. El objetivo de los genéricos (bueno, uno de los puntos) es usar seguridad de tipo de tiempo de compilación. ¡Aquí no sabes el tipo en tiempo de compilación! Puede llamar al método por reflexión (buscando el formulario abierto y luego llamando al MakeGenericMethod), pero eso es bastante feo.

¿Realmente necesita el DoStuff ser genérico en primer lugar? ¿Está siendo utilizado desde otro lugar? El parámetro PropertyInfo.SetValue es solo objeto, por lo que aún obtendría boxeo, etc. aunque podría llamar al método de forma genérica.

2

Si no usa DoStuff desde otro lugar, también sugiero que escriba un método no genérico.

Quizás haya creado el método genérico para poder usar el valor predeterminado (T). Para sustituir un método que no genérico, puede utilizar Activator.CreateInstance (T) para los tipos de valor y nulo para los tipos de referencia:

object defaultResult = type.IsValueType ? Activator.CreateInstance(type) : null 
Cuestiones relacionadas