2008-11-14 22 views
22

Estoy escribiendo un método Clone utilizando la reflexión. ¿Cómo puedo detectar que una propiedad es una propiedad indexada usando reflexión? Por ejemplo:C# Reflection Indexed Properties

public string[] Items 
{ 
    get; 
    set; 
} 

Mi método hasta ahora:

public static T Clone<T>(T from, List<string> propertiesToIgnore) where T : new() 
{ 
    T to = new T(); 

    Type myType = from.GetType(); 

    PropertyInfo[] myProperties = myType.GetProperties(); 

    for (int i = 0; i < myProperties.Length; i++) 
    { 
     if (myProperties[i].CanWrite && !propertiesToIgnore.Contains(myProperties[i].Name)) 
     { 
      myProperties[i].SetValue(to,myProperties[i].GetValue(from,null),null); 
     } 
    } 

    return to; 
} 
+13

Eso no es una propiedad indexada, que es una propiedad que devuelve una matriz. –

+3

Esta pregunta debe ser modificada por un moderador. Es el resultado superior de google para encontrar una propiedad del indexador, pero eso no es lo que ilustra el ejemplo del código. La mitad de las respuestas a continuación responden la pregunta y la mitad del código. –

Respuesta

40
if (propertyInfo.GetIndexParameters().Length > 0) 
{ 
    // Property is an indexer 
} 
8

Lo que queremos es el método GetIndexParameters(). Si la matriz que devuelve tiene más de 0 elementos, eso significa que es una propiedad indexada.

Ver the MSDN documentation para más detalles.

20

Lo sentimos, pero

public string[] Items { get; set; } 

es no una propiedad indexada, es simplemente de un tipo de matriz! Sin embargo, el siguiente es:

public string this[int index] 
{ 
    get { ... } 
    set { ... } 
} 
+1

Bien, pero ¿cómo lo encuentras a través de la reflexión? – BrainSlugs83

1

Aquí hay un código que trabajó para mí:

 
foreach (PropertyInfo property in obj.GetType().GetProperties()) 
{ 
    object value = property.GetValue(obj, null); 
    if (value is object[]) 
    { 
    .... 
    } 
} 

P. S. .GetIndexParameters().Length > 0) funciona para el caso descrito en este artículo: http://msdn.microsoft.com/en-us/library/b05d59ty.aspx Así que si le importa la propiedad llamada Chars para un valor de tipo cadena, utilícela, pero no funciona para la mayoría de las matrices que me interesan, incluido, estoy bastante seguro, una matriz de cadenas de la pregunta original.

2

Si llama al property.GetValue(obj,null) y la propiedad está indexada, obtendrá una excepción de discrepancia en el recuento de parámetros. Es mejor verificar si la propiedad está indexada usando GetIndexParameters() y luego decidir qué hacer.

0

Puede convertir el indexador de IEnumerable

public static IEnumerable<T> AsEnumerable<T>(this object o) where T : class { 
     var list = new List<T>(); 
     System.Reflection.PropertyInfo indexerProperty = null; 
     foreach (System.Reflection.PropertyInfo pi in o.GetType().GetProperties()) { 
      if (pi.GetIndexParameters().Length > 0) { 
       indexerProperty = pi; 
       break; 
      } 
     } 

     if (indexerProperty.IsNotNull()) { 
      var len = o.GetPropertyValue<int>("Length"); 
      for (int i = 0; i < len; i++) { 
       var item = indexerProperty.GetValue(o, new object[]{i}); 
       if (item.IsNotNull()) { 
        var itemObject = item as T; 
        if (itemObject.IsNotNull()) { 
         list.Add(itemObject); 
        } 
       } 
      } 
     } 

     return list; 
    } 


    public static bool IsNotNull(this object o) { 
     return o != null; 
    } 

    public static T GetPropertyValue<T>(this object source, string property) { 
     if (source == null) 
      throw new ArgumentNullException("source"); 

     var sourceType = source.GetType(); 
     var sourceProperties = sourceType.GetProperties(); 
     var properties = sourceProperties 
      .Where(s => s.Name.Equals(property)); 
     if (properties.Count() == 0) { 
      sourceProperties = sourceType.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic); 
      properties = sourceProperties.Where(s => s.Name.Equals(property)); 
     } 

     if (properties.Count() > 0) { 
      var propertyValue = properties 
       .Select(s => s.GetValue(source, null)) 
       .FirstOrDefault(); 

      return propertyValue != null ? (T)propertyValue : default(T); 
     } 

     return default(T); 
    } 
+0

Estoy pensando que esto solo maneja las propiedades de un solo entero-indexador, ¿verdad? no hay indexadores basados ​​en cadenas, no hay varios parámetros de índice ... ¿o me falta algo? –

+0

@CodeJockey - Puede estar en lo correcto; Tengo problemas para hacer que funcione con un tipo de entrada 'String'. Está colgando en la propiedad indexada 'Chars'. A menos que me esté perdiendo algo yo mismo ... – InteXX