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

服務(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

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 天天夜夜草草久久伊人天堂 | 小舞同人18av黄漫网站 | 国内精品哆啪啪 | 99ri国产精品 | gangbang日本 | 色婷婷六月丁香在线观看 | jzz大全部 | 日韩风月片| 娇喘高潮教室h | 亚洲第一综合天堂另类专 | 色婷婷激婷婷深爱五月老司机 | 色狠狠成人综合网 | 亚洲欧美精品一区天堂久久 | a色在线| 小SAO货边洗澡边CAO你动漫 | 日韩视频一区二区三区 | 天天成人 | 日本韩国一区二区三区 | 国产精品 视频一区 二区三区 | 78成人网| 久久久精品国产免费A片胖妇女 | 91大神大战高跟丝袜美女 | 日本国产一区二区三区 | 久久伊人影视 | 免费特黄视频 | 久久九九有精品国产23百花影院 | 国产在线91 | 婷婷色天使在线视频观看 | 3d动漫美女被吸乳羞羞有 | 久久久WWW免费人成精品 | 3d欧美人禽交 | 大陆日韩欧美 | 男人狂躁女人下面的视频免费 | 亚洲欧美日韩一区成人 | 翁息肉小说老扒 | 欧美一级裸片 | 色悠久久久 | 青青青久热国产精品视频 | 色综合 成人 | 香蕉在线精品一区二区 | 小鸟酱在线看 |