2011-02-25 82 views
1

我希望能夠按名稱訪問屬性或類的成員。我很好,如果它是一個屬性:使用反射(或其他方式)獲取成員對象

PropertyInfo prop = object.GetType().GetProperty(propertyName); 
    object propValue = prop.GetValue(object, null); 

事情似乎有點棘手,如果它是一個成員/字段。在學習GetMember並嘗試了一堆不同的東西時,我無法弄清楚如何獲得對象的引用,就像從GetProperty返回的那樣,如果它是屬性的話。

另一個問題是,這是完成這個的正確方法嗎?在閱讀反思時,它似乎有很多開銷。這僅僅是與不使用反射相比,還是足夠重要,我應該三思而後行開發一些可以做很多事情的東西,還有什麼替代方法可以獲得對某個成員的引用(如果有的話)只按名字上課?

感謝任何見解。如果它有什麼區別,我的目標是能夠序列化任意命名的屬性或類的成員。

回答

4

如果要檢索字段,則可以使用GetField而不是GetProperty

FieldInfo field = object.GetType().GetField(fieldName); 
object fieldValue = field.GetValue(Context.Parent); 

還是不夠,我應該三思開發的東西,會做這個有很多它顯著,做什麼選擇我,如果有的話,獲得的一類成員的引用只有名字?

這絕對是昂貴的,但我想知道它是否會有性能問題。

另一個主要選項是自己構建某種形式的字典,將「名稱」映射到值。這可以是直接映射到值的字典,也可以是映射到檢索值的代理的字典。這樣做的好處是可以使其對屬性或字段的工作方式相同,但每個類都需要創建映射。 (但是,這可以通過在施工時反射來完成)。

如果它有什麼區別,我的目標是能夠序列化任意命名的屬性或類的成員。

我會建議審查內置的Serialization Support,還有之前滾動自己的版本...

+0

太棒了,就是我在找的東西。這是序列化的Javascript,是的,我已經使用MS。性能在這一點上不是問題,但我正在設計這個功能時考慮可伸縮性。緩存的想法可能適用於此 - 儘管這是針對Web應用程序的。每次加載頁面時都需要訪問屬性。我認爲緩存代理不會跨頁加載,因爲對象不會是同一個實例。任何想法的方式來優化或緩存時,結構將堅持,但不是實例? – 2011-02-25 20:35:14

+0

@jamietre:你可以緩存一個考慮實例的代理(每個類型靜態),即:'Func ',然後將實例傳遞給代理以獲得值... – 2011-02-25 20:36:39

+0

@Reed Copsley - 我永遠不會需要多次訪問給定的實例。不過,我需要多次訪問同一個簽名的不同實例。也就是說,一旦我獲得了頁面加載的信息,我就完成了特定的頁面加載。這不會導致不斷增長的緩存,因爲每次「對象」都不一樣嗎?也許我誤解了你。 – 2011-02-25 20:41:42

0

如果您正在使用C#4.0(在.NET Framework 4.0和Visual Studio 2010一起發佈)新dynamic關鍵字,將簡化事情在你的代碼:

dynamic myValue = anyObject; 
string name = myValue.myField; // Resolved at runtime, not compile-time 
bool result = myValue.myBooleanMethod(1, 2, 3); // Ditto 

等等。我的理解是,這樣做更多或更少同樣的事情在引擎蓋下的使用反射和測試的兼容PropertyInfo存在/ MethodInfo /等。然後調用它們,所以性能仍然是一個問題,但它確實更具可讀性。

+0

我正在使用4.0 - 但我需要通過編譯時未知的名稱來訪問它們。 – 2011-02-25 20:44:05

0

我想出了緩存,評論歡迎。

public static ConcurrentDictionary<Tuple<Type, string>, 
     Func<object, object[], object>> ReflectionCache 
    { 
     get 
     { 
      if (_ReflectionCache==null) { 
       _ReflectionCache = new ConcurrentDictionary<Tuple<Type, string>, 
        Func<object, object[], object>>(); 
      } 
      return _ReflectionCache; 
     } 
    } private static ConcurrentDictionary<Tuple<Type, string>, 
     Func<object, object[], object>> _ReflectionCache = null; 

    public static object GetCachedProperty(object obj, string name) 
    { 
     Func<object,object[],object> del; 
     if (!ReflectionCache.TryGetValue(Tuple.Create<Type,string>(obj.GetType(), 
      name), out del)) { 
      MemberInfo memberInfo = 
       (MemberInfo)obj.GetType().GetMember(name).GetValue(0); 
      PropertyInfo prop = null; 
      FieldInfo fld = null; 

      switch(memberInfo.MemberType) { 
      case MemberTypes.Field: 
       fld = obj.GetType().GetField(name); 
       break; 
      case MemberTypes.Property: 
       prop = obj.GetType().GetProperty(name); 
       break; 
      } 

      if (prop == null && fld == null) 
      { 
       throw new Exception("No property or field named '" + name 
       + "' could be found in the context parent."); 
      } 
      if (prop!=null) { 
       prop= obj.GetType().GetProperty(name); 
       del = prop.GetValue; 
      } else { 
       fld = obj.GetType().GetField(name); 
       del = delegate(object cls,object[] index) { 
        return fld.GetValue(cls); 
       }; 
      } 

      ReflectionCache[Tuple.Create<Type,string>(obj.GetType(),name)]=del; 
     } 
     return(del(obj,null)); 
    } 
+0

對於屬性,可以在PropertyInfo的GetGetMethod上使用Delegate.CreateDelegate,這將避免反射開銷... – 2011-02-25 22:44:53

+0

很酷。再次感謝。我猜這對字段還是有好處的,因爲我只使用GetValue而不是GetField。 – 2011-02-25 22:55:40