一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - C# - 利用lambda表達(dá)式樹優(yōu)化反射詳解

利用lambda表達(dá)式樹優(yōu)化反射詳解

2022-03-06 13:32Fode C#

這篇文章主要給大家介紹了關(guān)于如何利用lambda表達(dá)式樹優(yōu)化反射的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

前言

本節(jié)重點(diǎn)不講反射機(jī)制,而是講lambda表達(dá)式樹來替代反射中常用的獲取屬性和方法,來達(dá)到相同的效果但卻比反射高效。

每個(gè)人都知道,用反射調(diào)用一個(gè)方法或者對屬性執(zhí)行setvalue和getvalue操作的時(shí)候都會(huì)比直接調(diào)用慢很多,這其中設(shè)計(jì)到clr中內(nèi)部的處理,不做深究。然而,我們在某些情況下又無法不使用反射,比如:在一個(gè)orm框架中,你要將一個(gè)datarow轉(zhuǎn)化為一個(gè)對象,但你又不清楚該對象有什么屬性,這時(shí)候你就需要寫一個(gè)通用的泛型方法來處理,以下代碼寫得有點(diǎn)惡心,但不妨礙理解意思:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
//將datareader轉(zhuǎn)化為一個(gè)對象
     private static t getobj<t>(sqlitedatareader reader) where t : class
 {
  t obj = new t();
  propertyinfo[] pros = obj.gettype().getproperties();
  foreach (propertyinfo item in pros)
  {
  try
  {
   int32 index = reader.getordinal(item.name);
   string result = reader.getstring(index);
   if (typeof(string) == item.propertytype)
   {
   item.setvalue(obj, result);
   continue;
   }
   if (typeof(datetime) == item.propertytype)
   {
   item.setvalue(obj, convert.todatetime(result));
   continue;
   }
   if (typeof(boolean) == item.propertytype)
   {
   item.setvalue(obj, convert.toboolean(result));
   continue;
   }
   if (typeof(int32) == item.propertytype)
   {
   item.setvalue(obj, convert.toint32(result));
   continue;
   }
   if (typeof(single) == item.propertytype)
   {
   item.setvalue(obj, convert.tosingle(result));
   continue;
   }
   if (typeof(single) == item.propertytype)
   {
   item.setvalue(obj, convert.tosingle(result));
   continue;
   }
   if (typeof(double) == item.propertytype)
   {
   item.setvalue(obj, convert.todouble(result));
   continue;
   }
   if (typeof(decimal) == item.propertytype)
   {
   item.setvalue(obj, convert.todecimal(result));
   continue;
   }
   if (typeof(byte) == item.propertytype)
   {
   item.setvalue(obj, convert.tobyte(result));
   continue;
   }
  }
  catch (argumentoutofrangeexception ex)
  {
   continue;
  }
  }
  return obj;
 }

對于這種情況,其執(zhí)行效率是特別低下的,具體多慢在下面例子會(huì)在.net core平臺上和.net framework4.0運(yùn)行測試案例.對于以上我舉例的情況,效率上我們還可以得到提升。但對于想在運(yùn)行時(shí)修改一下屬性的名稱或其他操作,反射還是一項(xiàng)特別的神器,因此在某些情況下反射還是無法避免的。

但是對于只是簡單的setvalue或者getvalue,包括用反射構(gòu)造函數(shù),我們可以想一個(gè)中繼的方法,那就是使用表達(dá)式樹。對于不理解表達(dá)式樹的,可以到微軟文檔查看,。表達(dá)式樹很容易通過對象模型表示表達(dá)式,因此強(qiáng)烈建議學(xué)習(xí)。查看以下代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
static void main()
 {
  dog dog = new dog();
  propertyinfo propertyinfo = dog.gettype().getproperty(nameof(dog.name)); //獲取對象dog的屬性
  methodinfo settermethodinfo = propertyinfo.getsetmethod(); //獲取屬性name的set方法
 
  parameterexpression param = expression.parameter(typeof(dog), "param");
  expression getpropertyvalueexp = expression.lambda(expression.property(param, nameof(dog.name)), param);
  expression<func<dog, string>> getpropertyvaluelambda = (expression<func<dog, string>>)getpropertyvalueexp;
  parameterexpression paramo = expression.parameter(typeof(dog), "param");
  parameterexpression parami = expression.parameter(typeof(string), "newvalue");
  methodcallexpression methodcallsetterofproperty = expression.call(paramo, settermethodinfo, parami);
  expression setpropertyvalueexp = expression.lambda(methodcallsetterofproperty, paramo, parami);
  expression<action<dog, string>> setpropertyvaluelambda = (expression<action<dog, string>>)setpropertyvalueexp;
 
  //創(chuàng)建了屬性name的get方法表達(dá)式和set方法表達(dá)式,當(dāng)然只是最簡單的
  func<dog, string> getter = getpropertyvaluelambda.compile();
  action<dog, string> setter = setpropertyvaluelambda.compile();
 
  setter?.invoke(dog, "wlj"); //我們現(xiàn)在對dog這個(gè)對象的name屬性賦值
  string dogname = getter?.invoke(dog); //獲取屬性name的值
  
  console.writeline(dogname);
  console.readkey();
 }
 
 public class dog
 {
  public string name { get; set; }
 }

以下代碼可能很難看得懂,但只要知道我們創(chuàng)建了屬性的get、set這兩個(gè)方法就行,其結(jié)果最后也能輸出狗的名字 wlj,擁有expressiontree的好處是他有一個(gè)名為compile()的方法,它創(chuàng)建一個(gè)代表表達(dá)式的代碼塊。現(xiàn)在是最有趣的部分,假設(shè)你在編譯時(shí)不知道類型(在這篇文章中包含的代碼我在不同的程序集上創(chuàng)建了一個(gè)類型)你仍然可以應(yīng)用這種技術(shù),我將對于常用的屬性的set,get操作進(jìn)行分裝。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/// <summary>
   /// 屬性類,仿造反射中的propertyinfo
 /// </summary>
   public class property
 {
 
  private readonly propertygetter getter;
  private readonly propertysetter setter;
  public string name { get; private set; }
 
  public propertyinfo info { get; private set; }
 
  public property(propertyinfo propertyinfo)
  {
   if (propertyinfo == null)
    throw new nullreferenceexception("屬性不能為空");
   this.name = propertyinfo.name;
   this.info = propertyinfo;
   if (this.info.canread)
   {
    this.getter = new propertygetter(propertyinfo);
   }
 
   if (this.info.canwrite)
   {
    this.setter = new propertysetter(propertyinfo);
   }
  }
 
 
  /// <summary>
     /// 獲取對象的值
  /// </summary>
    /// <param name="instance"></param>
    /// <returns></returns>
     public object getvalue(object instance)
  {
   return getter?.invoke(instance);
  }
 
 
  /// <summary>
     /// 賦值操作
  /// </summary>
    /// <param name="instance"></param>
    /// <param name="value"></param>
     public void setvalue(object instance, object value)
  {
   this.setter?.invoke(instance, value);
  }
 
  private static readonly concurrentdictionary<type, core.reflection.property[]> securitycache = new concurrentdictionary<type, property[]>();
 
  public static core.reflection.property[] getproperties(type type)
  {
   return securitycache.getoradd(type, t => t.getproperties().select(p => new property(p)).toarray());
  }
 
 }
 
  /// <summary>
   /// 屬性get操作類
  /// </summary>
    public class propertygetter
  {
  private readonly func<object, object> funcget;
 
  public propertygetter(propertyinfo propertyinfo) : this(propertyinfo?.declaringtype, propertyinfo.name)
  {
 
  }
 
  public propertygetter(type declaretype, string propertyname)
  {
   if (declaretype == null)
   {
    throw new argumentnullexception(nameof(declaretype));
   }
   if (propertyname == null)
   {
    throw new argumentnullexception(nameof(propertyname));
   }
 
 
 
   this.funcget = creategetvaluedeleagte(declaretype, propertyname);
  }
 
 
  //代碼核心部分
     private static func<object, object> creategetvaluedeleagte(type declaretype, string propertyname)
  {
   // (object instance) => (object)((declaringtype)instance).propertyname
 
       var param_instance = expression.parameter(typeof(object));
   var body_objtotype = expression.convert(param_instance, declaretype);
   var body_gettypeproperty = expression.property(body_objtotype, propertyname);
   var body_return = expression.convert(body_gettypeproperty, typeof(object));
   return expression.lambda<func<object, object>>(body_return, param_instance).compile();
  }
 
  public object invoke(object instance)
  {
   return this.funcget?.invoke(instance);
  }
 }
 
 
  public class propertysetter
 {
  private readonly action<object, object> setfunc;
 
  public propertysetter(propertyinfo property)
  {
   if (property == null)
 
   {
    throw new argumentnullexception(nameof(property));
   }
   this.setfunc = createsetvaluedelagate(property);
  }
 
 
 
  private static action<object, object> createsetvaluedelagate(propertyinfo property)
  {
   // (object instance, object value) =>
   //  ((instancetype)instance).set_xxx((propertytype)value)
 
   //聲明方法需要的參數(shù)
   var param_instance = expression.parameter(typeof(object));
   var param_value = expression.parameter(typeof(object));
 
   var body_instance = expression.convert(param_instance, property.declaringtype);
   var body_value = expression.convert(param_value, property.propertytype);
   var body_call = expression.call(body_instance, property.getsetmethod(), body_value);
 
   return expression.lambda<action<object, object>>(body_call, param_instance, param_value).compile();
  }
 
  public void invoke(object instance, object value)
  {
   this.setfunc?.invoke(instance, value);
  }
 }

在將代碼應(yīng)用到實(shí)例:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
dog dog = new dog();
propertyinfo propertyinfo = dog.gettype().getproperty(nameof(dog.name));
 
//反射操作
propertyinfo.setvalue(dog, "wlj");
string result = propertyinfo.getvalue(dog) as string;
console.writeline(result);
 
//表達(dá)式樹的操作
property property = new property(propertyinfo);
property.setvalue(dog, "wlj2");
string result2 = propertyinfo.getvalue(dog) as string;
console.writeline(result2);

發(fā)現(xiàn)其實(shí)現(xiàn)的目的與反射一致,但效率卻有明顯的提高。

以下測試以下他們兩之間的效率。測試代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
student student = new student();
propertyinfo propertyinfo = student.gettype().getproperty(nameof(student.name));
property expproperty = new property(propertyinfo);
 
int32 loopcount = 1000000;
codetimer.initialize(); //測試環(huán)境初始化
 
//下面該方法個(gè)執(zhí)行1000000次
 
codetimer.time("基礎(chǔ)反射", loopcount, () => {
 propertyinfo.setvalue(student, "fode",null);
});
codetimer.time("lambda表達(dá)式樹", loopcount, () => {
 expproperty.setvalue(student, "fode");
});
codetimer.time("直接賦值", loopcount, () => {
 student.name = "fode";
});
console.readkey();

其.net4.0環(huán)境下運(yùn)行結(jié)果如下:

利用lambda表達(dá)式樹優(yōu)化反射詳解

.net core環(huán)境下運(yùn)行結(jié)果:

利用lambda表達(dá)式樹優(yōu)化反射詳解

從以上結(jié)果可以知道,迭代同樣的次數(shù)反射需要183ms,而用表達(dá)式只要34ms,直接賦值需要7ms,在效率上,使用表達(dá)式這種方法有顯著的提高,您可以看到使用此技術(shù)可以完全避免使用反射時(shí)的性能損失。反射之所以效率有點(diǎn)低主要取決于其加載的時(shí)候時(shí)在運(yùn)行期下,而表達(dá)式則在編譯期,下篇有空將會(huì)介紹用emit技術(shù)優(yōu)化反射,會(huì)比表達(dá)式略快一點(diǎn)。

注:對于常用對象的屬性,最好將其緩存起來,這樣效率會(huì)更高。。

代碼下載

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對服務(wù)器之家的支持。

原文鏈接:https://www.cnblogs.com/fode/p/10079630.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 欧美精品一区二区三区久久 | se01在线看片 | 亚洲阿v天堂在线2017 | 亚洲免费一 | 欧美理论片手机在线观看片免费 | 3p文两男一女办公室高h | 美女靠逼的视频 | 调教女高中生第3部分 | 成人啪精品视频免费网站 | 韩国美女豪爽一级毛片 | 青青青国产 | 俄罗斯美女大逼 | 吻戏辣妞范1000免费体验 | 国产香蕉一区二区在线网站 | 色综合天天综合 | 国产成人咱精品视频免费网站 | 2012中文字幕中字视频 | 色偷偷伊人| 天天综合色网 | 91噜噜噜在线观看 | 91看片淫黄大片欧美看国产片 | 久久免费看少妇高潮A片JA | 精品手机在线视频 | 2018久久精品热在线观看 | 四虎免费在线观看 | 精品国产三级av在线 | 日韩免费视频播播 | 天使萌痴汉在线中文字幕 | 91制片厂制作果冻传媒八夷 | 校园高h | 紧身牛仔裤美女被啪啪久久网 | tk白嫩玉足脚心vk | 欧美贵妇vs高跟办公室 | 91精品手机国产露脸 | 果冻传媒在线播放观看w | 精品久久伦理中文字幕 | 草莓视频网站18勿进 | 久久成人国产精品一区二区 | 久久久影院亚洲精品 | 99视频免费在线 | 十六以下岁女子毛片免费 |