2008-11-14 11 views
22

J'écris une méthode de clonage en utilisant la réflexion. Comment puis-je détecter qu'une propriété est une propriété indexée en utilisant la réflexion? Par exemple:Propriétés indexées par réflexion C#

public string[] Items 
{ 
    get; 
    set; 
} 

Ma méthode à ce jour:

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

Ce n'est pas une propriété indexée, qui est une propriété qui retourne un tableau. –

+3

Cette question doit être modifiée par un modérateur. C'est le meilleur résultat google pour trouver une propriété d'indexeur mais ce n'est pas ce que l'exemple de code illustre. La moitié des réponses ci-dessous répondent à la question et la moitié de l'exemple de code. –

Répondre

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

Ce que vous voulez est la méthode GetIndexParameters(). Si le tableau qu'il renvoie contient plus de 0 élément, cela signifie qu'il s'agit d'une propriété indexée.

Voir the MSDN documentation pour plus de détails.

20

Désolé, mais

public string[] Items { get; set; } 

est pas une propriété indexée, il est simplement d'un type de tableau! Cependant ce qui suit est:

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

D'accord, mais comment le trouvez-vous par réflexion? – BrainSlugs83

1

Voici un code qui a fonctionné pour moi:

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

post-scriptum .GetIndexParameters().Length > 0) Fonctionne pour le cas décrit dans cet article: http://msdn.microsoft.com/en-us/library/b05d59ty.aspx Donc, si vous vous souciez de la propriété Chars pour une valeur de type chaîne, utilisez-la, mais cela ne fonctionne pas pour la plupart des tableaux qui m'intéressaient, y compris, je suis assez sûr, un tableau de chaînes de la question d'origine.

2

Si vous appelez property.GetValue(obj,null) et que la propriété IS est indexée, vous obtiendrez une exception de discordance de nombre de paramètres. Mieux vaut vérifier si la propriété est indexée en utilisant GetIndexParameters() et ensuite décider quoi faire.

0

Vous pouvez convertir l'indexeur à 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

Je pense que cela ne gère que les propriétés single-integer-indexer, non? pas d'indexeurs basés sur des chaînes, pas de paramètres d'index multiples ... ou ai-je oublié quelque chose? –

+0

@CodeJockey - Vous avez peut-être raison; J'ai du mal à le faire fonctionner avec un type d'entrée 'String'. Il raccroche sur la propriété indexée 'Chars'. A moins que je ne manque quelque chose moi-même ... – InteXX