C 使用反射獲取私有屬性的方法

2021-10-03 21:33:27 字數 4069 閱讀 6009

c# 使用反射獲取私有屬性的方法

indexi_gd

本文告訴大家多個不同的方法使用反射獲得私有屬性,最後通過測試效能發現所有的方法的效能都差不多

在開始之前先新增乙個測試的類

public class foo = "123";

}

如果需要拿到 foo 的 屬性 f 可以通過 propertyinfo 直接拿到,從乙個類拿到對應的 propertyinfo 可以通過下面的**

var foo = new foo();

var type = foo.gettype();

const bindingflags instancebindflags = bindingflags.instance | bindingflags.public | bindingflags.nonpublic;

var propertyname = "f";

propertyinfo property = type.getproperty(propertyname, instancebindflags);

if (property == null)

實際上可能在 type.getproperty 還拿不到 property 需要通過不斷找到基類

propertyinfo property = null;

while (type != null)

type = type.basetype;

}if (property == null)

現在就獲得了 propertyinfo 通過這個屬性可以拿到類的屬性,這裡拿到屬性有三個不同的方法

getvalue

getgetmethod

getaccessor

其中最簡單的是通過 getvalue 的方法,請看下面

getvalue

最簡單的方法直接呼叫 getvalue 的方法

var f = property.getvalue(foo);12

這裡的 f 就是屬性

getgetmethod

這裡的兩個 get 不是寫錯了,而是拿到 get 方法的意思,也就是需要屬性有 get 方法才可以使用下面**

methodinfo getter = property.getgetmethod(nonpublic: true);

var f = getter.invoke(foo, null);12

通過 getgetmethod 可以拿到 methodinfo 方法,如果對屬性的返回值是可見的,如上面的 foo 是使用 string 作為屬性的類,可以通過建立委託的方式提高效能。

如果對於屬性的返回值是不可見的,也就是返回值是拿不到的,就無法通過建立委託的方式提高效能。

getaccessor

最後乙個方法是通過 getaccessor 訪問器的方法,需要引用表示式

///

/// 獲取 的給定 屬性的獲取方法

///

///

/// 屬性名,屬性可以是私有

///

/// 屬性的 get 方法,傳入對應的例項返回屬性

///

/// var f = new f();

/// var getaccessor = getpropertygetaccessor(f.gettype(), "privateproperty");

/// getaccessor(f);// 獲取屬性

///

///

[pure]

public static funcgetpropertygetaccessor([notnull] type type, [notnull] string propertyname)

var method = property.getgetmethod(true);

var obj = expression.parameter(typeof(object), "o");

debug.assert(method.declaringtype != null);

expression> expression =

expression.lambda>

(expression.convert

(expression.call

(expression.convert(obj, method.declaringtype),

method

),typeof(object)

),obj

);return expression.compile();

}通過這個方法可以建立乙個委託出來,通過這個委託可以拿到很高的效能,在下面我測試了不同的方法的效能

測試首先是通過 getvalue 的方式經過 1 次 和 100 次執行,測試方法都是通過c# 標準效能測試 但是在測試完成需要告訴大家結論

使用 getvalue 的方式和使用其他幾個反射拿到屬性的方法的效能都是差不多的,所以不需要對私有屬性反射去優化

method    categories    mean    error    stddev

'getproperty 呼叫1次反射'    1次呼叫    205.5 ns    2.882 ns    2.555 ns

'getproperty 呼叫100次反射'    100次呼叫    20,059.9 ns    121.177 ns    113.349 ns

因為 getvalue 沒有使用快取的方法,而快取也只是快取 propertyinfo 的值,於是在下面測試 getgetmethod 的方法,這個方法在跑100次就新增了快取

public void getpropertygetaccessormethodinfo_call100()

type = type.basetype;

}if (property == null)

methodinfo getter = property.getgetmethod(nonpublic: true);

for (int i = 0; i < 100; i++)

}執行測試可以看到

method    categories    mean    error    stddev

'getpropertgetaccessormethodinfo 呼叫一次'    1次呼叫    191.6 ns    0.7641 ns    0.6774 ns

'getpropertgetaccessormethodinfo 呼叫100次'    100次呼叫    10,341.9 ns    134.9177 ns    126.2021 ns

相對於 getvalue 沒有帶快取的 getgetmethod 帶快取的效能是 getvalue 的一倍,也就是找到 propertyinfo 占用的時間如果能減少,就可以提高速度。

最後通過 getpropertygetaccessor 建立委託,然後快取委託的方式呼叫 1 次和 100 次。在呼叫 1 次的過程是包括第一次初始化的時間,而呼叫 100 次是包括和不包括第一次初始化

method    categories    mean    error    stddev

'getpropertygetaccessor 呼叫一次'    1次呼叫    206,282.4 ns    4,051.754 ns    5,939.008 ns

'getpropertygetaccessor 呼叫100次'    100次呼叫    222,227.4 ns    4,354.600 ns    6,906.857 ns

'getpropertgetaccessormethodinfo 帶快取呼叫100次'    100次呼叫    10,352.2 ns    141.629 ns    132.480 ns

可以看到 getpropertygetaccessor 方法在初始化的時間很長,而帶快取的呼叫和 getgetmethod 的方法呼叫的時間幾乎一樣長

建議反射私有屬性使用 getvalue 的方法,因為只要呼叫非公有屬性,呼叫的時間就是這麼長,無論通過表示式或其他方法都無法減少時間。如果遇到需要提高反射屬性的速度,建議修改屬性為公開,這時可以通過 fast member 快速拿到屬性

C 使用反射獲取私有屬性的方法

目錄 c 使用反射獲取私有屬性的方法 getvalue getgetmethod getaccessor 測試2019年04月16日 10 15 23 lindexi gd 閱讀數 156 在開始之前先新增乙個測試的類 public class foo 123 var foo new foo var...

反射dll獲取類屬性方法

assembly asb assembly.loadfrom directory.getcurrentdirectory document.dll 獲取程式集下面的document類 type document asb.gettype document.document 例項化document類物件...

C 反射設定屬性值和獲取屬性值

獲取類中的屬性值 public string getmodelvalue string fieldname,object obj catch 設定類中的屬性值 public bool setmodelvalue string fieldname,string value,object obj cat...