2008-12-14 4 views

cevap

41

Sen gibi bir şey gerekir: Eğer bir dize "Address.ZipCode" alıp aşağı gezinmek istiyorsanız Temelde

PropertyInfo addressProperty = typeof(Customer).GetProperty("Address"); 
ProportyInfo zipCodeProperty = addressProperty.PropertyType.GetProperty("ZipCode"); 

object address = addressProperty.GetValue(customer, null); 
object zipCode = zipCodeProperty.GetValue(address, null); 

, bunu bölmek gerekir tarafından "." ve daha sonra GetProperty, her adımda, mülkün kendisini almak için her adımda uygun türü arayın, sonra zincirinde bir sonraki değeri almak için PropertyInfo.GetValue. Böyle bir şey: böyle

public static object FollowPropertyPath(object value, string path) 
{ 
    Type currentType = value.GetType(); 

    foreach (string propertyName in path.Split('.')) 
    { 
     PropertyInfo property = currentType.GetProperty(propertyName); 
     value = property.GetValue(value, null); 
     currentType = property.PropertyType; 
    } 
    return value; 
} 

Çağrı it: Bu özelliklerin derleme zamanı türleri üzerinde çalıştığı

object zipCode = FollowPropertyPath(customer, "Address.ZipCode"); 

Not. Yürütme zamanı türüyle başa çıkmak istiyorsanız (ör. Customer.Address öğesinin bir ZipCode özelliği yoksa, bu adres tarafından döndürülen gerçek tür yoksa) property.PropertyType değerini property.GetType() olarak değiştirin.

Ayrıca, bu işleme herhangi bir hata vs :)

+0

Nice answer! ... Superlike. – Hrishi

2
typeof (Customer).GetProperty("Address").PropertyType.GetProperty("ZipCode") 
5

mevcut cevaplar gayet yoktur unutmayın; sadece alternatif bir perspektif: birçok senaryoda, çalışma zamanı özellik senaryoları için izin verdiği gibi doğrudan yansımadan ziyade System.ComponentModel kullanılması arzu edilir - yani DataTable'ın DataView sütunları özellikleri olarak gösterir.

Performans bilgisi - varsayılan olarak büyük ölçüde aynıdır, ancak bunun çoğunu yapıyorsanız (örneğin, toplu veri içe aktarma/dışa aktarma), aslında bu yaklaşımı kullanarak HyperDescriptor izniyle önemli performans artışları elde edebilirsiniz. System.ComponentModel kullanmak için

, kod benzer, ancak ustaca farklıdır: Eğer "Address.ZipCode" bağlanma veri bağlama kullanıldığı sanki bu daha sonra sana aynı tutuşu sağlar

static void Main() 
{ 
    object obj = new Customer { Address = new Address { ZipCode = "abcdef" } }; 

    object address = GetValue(obj, "Address"); 
    object zip = GetValue(address, "ZipCode"); 

    Console.WriteLine(zip); 
} 
static object GetValue(object component, string propertyName) 
{ 
    return TypeDescriptor.GetProperties(component)[propertyName].GetValue(component); 
} 

(Listeler vb. (Bu veri bağlayıcı kullanımları ele aynı listede dahil) derin bir yoldan değeri elde etmek

(bunu beklenen türüdür biliyorsanız dize vb zip düşürebilir notu)

, olur gibi bir şey kullanın:

static object ResolveValue(object component, string path) { 
    foreach(string segment in path.Split('.')) { 
     if (component == null) return null; 
     if(component is IListSource) { 
      component = ((IListSource)component).GetList(); 
     } 
     if (component is IList) { 
      component = ((IList)component)[0]; 
     } 
     component = GetValue(component, segment); 
    } 
    return component; 
} 

kabaca davranışını aynalar liste şeyler düzenli veri bağlama

6

Jon Skeet en (o bağlayıcı-bağlamlarda, döviz-yöneticileri, vb gibi bir kaç şey atlar rağmen) Cevap gayet iyi, mülkiyet yol içindeki türetilmiş örnekleri dikkate amacıyla, biraz olsa onun yöntemini uzatmak zorunda kaldı:

public static class ReflectorUtil 
{ 
    public static object FollowPropertyPath(object value, string path) 
    { 
     if (value == null) throw new ArgumentNullException("value"); 
     if (path == null) throw new ArgumentNullException("path"); 

     Type currentType = value.GetType(); 

     object obj = value; 
     foreach (string propertyName in path.Split('.')) 
     { 
      if (currentType != null) 
      { 
       PropertyInfo property = null; 
       int brackStart = propertyName.IndexOf("["); 
       int brackEnd = propertyName.IndexOf("]"); 

       property = currentType.GetProperty(brackStart > 0 ? propertyName.Substring(0, brackStart) : propertyName); 
       obj = property.GetValue(obj, null); 

       if (brackStart > 0) 
       { 
        string index = propertyName.Substring(brackStart + 1, brackEnd - brackStart - 1); 
        foreach (Type iType in obj.GetType().GetInterfaces()) 
        { 
         if (iType.IsGenericType && iType.GetGenericTypeDefinition() == typeof(IDictionary<,>)) 
         { 
          obj = typeof(ReflectorUtil).GetMethod("GetDictionaryElement") 
               .MakeGenericMethod(iType.GetGenericArguments()) 
               .Invoke(null, new object[] { obj, index }); 
          break; 
         } 
         if (iType.IsGenericType && iType.GetGenericTypeDefinition() == typeof(IList<>)) 
         { 
          obj = typeof(ReflectorUtil).GetMethod("GetListElement") 
               .MakeGenericMethod(iType.GetGenericArguments()) 
               .Invoke(null, new object[] { obj, index }); 
          break; 
         } 
        } 
       } 

       currentType = obj != null ? obj.GetType() : null; //property.PropertyType; 
      } 
      else return null; 
     } 
     return obj; 
    } 

    public static TValue GetDictionaryElement<TKey, TValue>(IDictionary<TKey, TValue> dict, object index) 
    { 
     TKey key = (TKey)Convert.ChangeType(index, typeof(TKey), null); 
     return dict[key]; 
    } 

    public static T GetListElement<T>(IList<T> list, object index) 
    { 
     return list[Convert.ToInt32(index)]; 
    } 

} 

property.PropertyType size obj sınıfında tanımlanan özellik türünü alacak kullanarak, süre obj.GetType() kullanarak mülkün örneğinin gerçek türünü alırsınız.

DÜZENLEME: @Oliver - kesinlikle haklısınız, bunu bildirdiğiniz için teşekkür ederiz. Genel Listeler ve Sözlükler için izin vermek için yöntemi ayarladı. Ayrıştırma parçasını beğenmemekle birlikte, indeksleyici özelliklerinin değerlerini almak için Marc Gravell'in zekice düşüncesini this thread numaralı telefondan kullandım. Eğer gerçek bir nesne örneği yoksa

+1

, yola girmeyi beklediğiniz şeye bağlı olarak, dizine eklenmiş mülklerde başarısız olursunuz (ör. "SomePerson.Adresses [3] .Street') – Oliver

1

adabyron,

Ben sadece türlerini kapmak gerektiğinde için kod versiyonunu yarattı ve.

public static Type FollowPropertyPath<T>(string path) 
    { 
     if (path == null) throw new ArgumentNullException("path"); 

     Type currentType = typeof(T); 

     foreach (string propertyName in path.Split('.')) 
     { 
      int brackStart = propertyName.IndexOf("["); 

      var property = currentType.GetProperty(brackStart > 0 ? propertyName.Substring(0, brackStart) : propertyName); 

      if (property == null) 
       return null; 

      currentType = property.PropertyType; 

      if (brackStart > 0) 
      { 
       foreach (Type iType in currentType.GetInterfaces()) 
       { 
        if (iType.IsGenericType && iType.GetGenericTypeDefinition() == typeof (IDictionary<,>)) 
        { 
         currentType = iType.GetGenericArguments()[1]; 
         break; 
        } 
        if (iType.IsGenericType && iType.GetGenericTypeDefinition() == typeof (ICollection<>)) 
        { 
         currentType = iType.GetGenericArguments()[0]; 
         break; 
        } 
       } 
      } 
     } 

     return currentType; 
    } 
İlgili konular