2012-10-01 17 views
19

Bu bir yerde ele alınmışsa özür dilerim. İlan etmeden önce araştırma yaptım!Yansıma yoluyla tek bir çağrıyla hem alanları hem de özellikleri nasıl alabilirim?

tamam, bu yüzden soru ... GetType() .GetProperties kullanıyorum, ancak bunlara alma/ayarlama yapmayan basit örnek alanları döndürmüyor ... bu yüzden .GetFields kullanıyorum. onları bulur, ancak alanlar ve özellikler arasında geçiş yapmadan bir değer elde etmek/ayarlamak için basit bir tek nesne almak istiyorum ... bu mümkün mü?

Güncel kodum harika çalışıyor, PropertyInfo üzerinde çalışıyor, ancak sanırım alanlar için değil?

[değiştir] Bu, iyi çalıştığım bir çözümdür. Fark etmiş görünmektedir olarak herkese teşekkürler .... GetProperties() ve GetFields() ait

// some logic borrowed from James Newton-King, http://www.newtonsoft.com 
    public static void SetValue(this MemberInfo member, object property, object value) 
    { 
     if (member.MemberType == MemberTypes.Property) 
      ((PropertyInfo)member).SetValue(property, value, null); 
     else if (member.MemberType == MemberTypes.Field) 
      ((FieldInfo)member).SetValue(property, value); 
     else 
      throw new Exception("Property must be of type FieldInfo or PropertyInfo"); 
    } 

    public static object GetValue(this MemberInfo member, object property) 
    { 
     if (member.MemberType == MemberTypes.Property) 
      return ((PropertyInfo)member).GetValue(property, null); 
     else if (member.MemberType == MemberTypes.Field) 
      return ((FieldInfo)member).GetValue(property); 
     else 
      throw new Exception("Property must be of type FieldInfo or PropertyInfo"); 
    } 

    public static Type GetType(this MemberInfo member) 
    { 
     switch (member.MemberType) 
     { 
      case MemberTypes.Field: 
       return ((FieldInfo)member).FieldType; 
      case MemberTypes.Property: 
       return ((PropertyInfo)member).PropertyType; 
      case MemberTypes.Event: 
       return ((EventInfo)member).EventHandlerType; 
      default: 
       throw new ArgumentException("MemberInfo must be if type FieldInfo, PropertyInfo or EventInfo", "member"); 
     } 
    } 

cevap

22

nereden:

const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance; 
MemberInfo[] members = type.GetFields(bindingFlags).Cast<MemberInfo>() 
    .Concat(type.GetProperties(bindingFlags)).ToArray(); 

Alternatif FastMember gibi kütüphaneler get ya alan ya da özellikleri ile mutlu çalışacaktır/bakılmaksızın üye tipi özdeş ayarlayın.

+0

OP'den: "bir değer almak/ayarlamak için basit bir tek nesne edinin". MemberInfo'nun bunu nasıl yaptığından emin değilim. – CrazyCasta

+1

@CrazyCasta gerçekten; İsterseniz, çekirdek yansıma API'sinin dışına çıkmanız gerekir * bunun için * paylaşılan bir arayüz yoktur. Ancak, ayrı kütüphaneler var, bu yüzden FastMember'i alıntıladım. –

+1

İkisi de yararlı olduğu için hem @CrazyCasta hem de marc'ı işaretlemek isterim, ama sonuç olarak MemberInfo ile uzantı yöntemlerini kullanarak yaptım. – Timmerz

10

dönüş türleri farklıdır. GetValue() ve SetValue() ile bir arabirim tanımlamanız ve bu arabirimi uygulamak için ParameterInfo ve FieldInfo kullanımını genişletmeniz gerekir. Bu muhtemelen bir sarıcı olarak çalışacak: Bu GetType().GetParametersAndFields() yapmanızı sağlayacaktır

interface IGetSettable 
{ 
    public void SetValue(
     Object obj, 
     Object value, 
     Object[] index); 
    public Object GetValue(
     Object obj, 
     Object[] index); 
} 

public class ParameterInfoGS : IGetSettable 
{ 
    protected ParameterInfo pi; 

    public ParameterInfoExtra(ParameterInfo _pi) 
    { 
     pi = _pi; 
    } 

    public void SetValue(
     Object obj, 
     Object value, 
     Object[] index) {pi.SetValue(obj, value, index);} 
    public Object GetValue(
     Object obj, 
     Object[] index) {return pi.GetValue(obj, index);} 
} 

public class FieldInfoGS : IGetSettable 
{ 
    protected FieldInfo pi; 

    public FieldInfoExtra(FieldInfo _pi) 
    { 
     pi = _pi; 
    } 

    public void SetValue(
     Object obj, 
     Object value, 
     Object[] index) {pi.SetValue(obj, value, index);} 
    public Object GetValue(
     Object obj, 
     Object[] index) {return pi.GetValue(obj, index);} 
} 

public static class AssemblyExtension 
{ 
    public static IGetSettable[] GetParametersAndFields(this Type t) 
    { 
     List<IGetSettable> retList = new List<IGetSettable>(); 

     foreach(ParameterInfo pi in t.GetParameters()) 
      retList.Add(new ParameterInfoExtra(pi)); 

     foreach(FieldInfo fi in t.GetFields()) 
      retList.Add(new FieldInfoExtra(fi)); 

     return retList.ToArray(); 
    } 
} 

(yani standart yansıma türlerini kullanın).

((dynamic)obj).MyFieldOrPropertyName = myValue; 

yalnızca çalışma zamanında de üye adını biliyorsanız, ben Marc olarak, FastMember öneriyoruz: (Derleme zamanında üye adını biliyorsanız yeterince basit,) DLR kullanma

+3

'MemberInfo'; p –

+4

@MarcGravell Bu yöntemlere ulaşma ve ayarlama. – CrazyCasta

2

Gravell önerdi.

6

Biraz geç ama şu ... 1 döngü ile geldi ya özelliklerini veya alanları almak için bir cazibe ;-)

 MemberInfo[] memberInfos = dotNetType.GetMembers(); 
     ModelPropertySpec modelPropertySpec; 
     foreach (MemberInfo memberInfo in memberInfos) 
     { 
      Type itemType = null; 
      String memberName = memberInfo.Name; 
      switch (memberInfo.MemberType) 
      { 
       case MemberTypes.Property: 
        itemType = dotNetType.GetProperty(memberName).PropertyType; 
        break; 
       case MemberTypes.Field: 
        itemType = dotNetType.GetField(memberName).FieldType; 
        break; 
      } 

      if (itemType != null) 
      { 
       modelPropertySpec = ParsePropertyType(memberName, itemType); 
       modelSpec.Properties.Add(modelPropertySpec.Name, modelPropertySpec); 
      } 
     } 
5

gibi çalışır, şunları söyleyebilirsiniz:

var q= 
    from it in type.GetMembers(bindingAttr) 
    where it is PropertyInfo||it is FieldInfo 
    select it; 

bindingAttr olmayan pu almak istemiyorsanız

var bindingAttr= 
     BindingFlags.NonPublic| 
     BindingFlags.Public| 
     BindingFlags.Instance; 

BindingFlags.NonPublic Kaldır nerede olabileceklerini blic üyeleri. Bu arada, sorgu tek bir çağrı ancak tek bir bildirimi ifade değil.


, kendiniz çevrim olmadan bir özellik veya bir alanın ya değerini almak numara için InvokeMember kullanmak için: Benzer

static object GetValue<T>(
     T x, object target) where T:MemberInfo { 
    var invokeAttr=(
      x is FieldInfo 
       ?BindingFlags.GetField 
       :x is PropertyInfo 
        ?BindingFlags.GetProperty 
        :BindingFlags.Default)| 
      BindingFlags.NonPublic| 
      BindingFlags.Public| 
      BindingFlags.Instance; 

    return target.GetType().InvokeMember(
     x.Name, invokeAttr, default(Binder), target, null); 
} 

, değerini ayarlamak için:

static void SetValue<T>(
     T x, object target, object value) where T:MemberInfo { 
    var args=new object[] { value }; 
    var invokeAttr=(
      x is FieldInfo 
       ?BindingFlags.SetField 
       :x is PropertyInfo 
        ?BindingFlags.SetProperty 
        :BindingFlags.Default)| 
      BindingFlags.NonPublic| 
      BindingFlags.Public| 
      BindingFlags.Instance; 

    target.GetType().InvokeMember(
     x.Name, invokeAttr, default(Binder), target, args); 
} 

BindingFlags.Default, "BindingFlags.Default doesn ', MemberInfo, PropertyInfo veya FieldInfo dışında bir ilk iletiyi geçirirseniz atar. ne yapacağını belirt.

İlgili konular