使用表示式樹和反射來訪問物件屬性的效能比較

2021-09-25 23:40:07 字數 2837 閱讀 1978

今天在工作上遇到這麼個需求:需要獲取物件上所有屬性的值,但並事先並不知道物件的型別。 我的第一反應就是使用反射,但是這個操作會進行多次,大量的反射肯定會有效能影響。雖然對我這個專案無關緊要,但我還是選擇了另外一種解決方案:構建表示式樹,再生成委託,然後將委託快取在字典裡。**如下:

首先構建表示式樹(類似這種形式:'(a) => a.xx'),並生成委託:

private static funcbuilddynamicgetpropertyvaluedelegate(propertyinfo property)

接著,當需要獲取屬性的值時,先在字典裡檢視是否有已經生成好的委託,有的話取出委託執行獲取屬性值。沒有則構建表示式樹生成委託,並放入字典中:

private static dictionarydelegatecache = new dictionary();

public static object getpropertyvalueuseexpression(tobject obj, propertyinfo property)

var getvaluedelegate = builddynamicgetpropertyvaluedelegate(property);

delegatecache[property] = getvaluedelegate;

return getvaluedelegate(obj);

}

就這麼簡單,完成之後,我想測試一下表示式樹版本和反射版本的效能差距如何,於是我又簡單實現反射版本作為測試對比:

public static object getpropertyvalueusereflection(tobject obj, propertyinfo propertyinfo)

接下來是兩者的測試**:

class car 

public string model

public int capacity

}.....

int repeattimes = 10000;

propertyinfo property = typeof(car).getproperty("make");

car car = new car();

stopwatch stopwatch = stopwatch.startnew();

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

stopwatch.stop();

console.writeline("repeated , cache in dictionary expression used time: ms", repeattimes, stopwatch.elapsedticks);

stopwatch.reset();

stopwatch.start();

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

stopwatch.stop();

console.writeline("repeated , reflection used time: ms", repeattimes, stopwatch.elapsedticks);

在我的預想之中是這樣的:表示式樹版本在呼叫次數很少的情況下會慢於反射版本,隨著次數增多,表示式樹版本的優勢會越來越明顯。

測試結果:

在呼叫次數為十萬、百萬、千萬次的情況下,表示式書版本的優勢隨著次數而提高。

ps:之前在**中犯了一些錯誤導致表示式樹版本的效率比反射還低,還把原因歸結於dictionary的效率,確實不該。但是為何這些小錯誤會導致如此的差距我還沒弄明白,搞明白之後再寫一篇部落格吧。

更新:

經過echofool、zhaxg兩位園友的提示,其實訪問屬性的委託可以不用放在字典裡,而是通過多接收乙個引數再根據switch case來獲取相應的屬性值,**如下:

public class propertydynamicgetter

}public object execute(t obj, string propertyname)

private funcbuilddynamicgetdelegate(propertyinfo properties)

//set null when default

var defaultbodyexpression = expression.assign(variableexpression, expression.constant(null));

var switchexpression = expression.switch(nameparamexpression, defaultbodyexpression, switchcases.toarray());

var blockexpression = expression.block(typeof(object), new , switchexpression);

var lambdaexpression = expression.lambda>(blockexpression, objparamexpression, nameparamexpression);

return lambdaexpression.compile();}}

這個版本不使用字典,從而去除了從字典取物件的影響。它實現上先是取出物件所有的屬性,然後在構建表示式樹時根據屬性名使用switch。

測試結果:

可以看到,在千萬次的情況下(十萬,百萬也是如此),這個版本效率比表示式樹快取在字典裡的效率還要高一些。

使用表示式樹和反射來訪問物件屬性的效能比較

今天在工作上遇到這麼個需求 需要獲取物件上所有屬性的值,但並事先並不知道物件的型別。我的第一反應就是使用反射,但是這個操作會進行多次,大量的反射肯定會有效能影響。雖然對我這個專案無關緊要,但我還是選擇了另外一種解決方案 構建表示式樹,再生成委託,然後將委託快取在字典裡。如下 首先構建表示式樹 類似這...

使用C 和Thrift來訪問Hbase例項

今天試著用c 和thrift來訪問hbase,主要參考了上的這篇文章。查了thrift,hbase的資料,結合的這篇文章,終於搞好了。期間經歷了不少彎路,下面我盡量詳細的記錄下來,免得大家走彎路。hbase 0.94.1 vs2012 netframework 4.0 一定要注意各產品的版本號,不同...

正規表示式和反射

1 什麼是正規表示式?就是對你想要操作的字串指定操作格式。2 為什麼要用它?簡化對字串的操作。3 如何用它?實際上就是對字串函式裡面傳指定規則的正規表示式。匹配 利用matches 正規表示式 切割 split 正規表示式 替代 replaceall 正規表示式 獲取 1,獲取pattern類例項 ...