第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定

晚綁定場(chǎng)景下對(duì)象屬性賦值和取值可以不需要PropertyInfo

標(biāo)簽:
產(chǎn)品

在《一句代码实现批量数据绑定》中,我通过界面控件ID与作为数据源的实体属性名之间的映射实现了批量数据绑定。由于里面频繁涉及对属性的反射——通过反射从实体对象中获取某个属性值;通过反射为控件的某个属性赋值,所以这不是一种高效的操作方式。为了提升性能,我通过IL Emit的方式创建了一个PropertyAccessor组件,以实现高效的属性操作。如果你看了我在文中给出的三种属性操作性能的测试结果,相信会对PropertyAccessor的作用有深刻的印象。[源代码从这里下载]

目录:      
一、PropertyAccessor与PropertyAccessor<T>的API定义      
二、如何通过PropertyAccessor获取属性值和为属性赋值      
三、Set和Get的实现      
四、比较三种属性操作的性能      
五、PropertyAccessor的ExpressionTree版本

一、PropertyAccessor与PropertyAccessor<T>的API定义

我们照例从编程——即如何使用PropertyAccessor进行属性操作(获取属性值/为属性赋值)讲起,所有先来看看PropertyAccessor提供了哪些API功我们调用。从下面的代码片断我们可以看到,PropertyAccessor得构造函数接受两个参数:目标对象的类型和属性名称,然后通过Get获取目标对象相应属性的值,通过Set方法为目标对象的属性进行赋值。此外,PropertyAccessor还提供了两个对应的Get/Set静态方法通过指定具体的目标对象和属性名称实现相同的操作。

   1: public class PropertyAccessor

   

   2: {

   

   3:     public PropertyAccessor(Type targetType, string propertyName);

   

   4:

   

   5:     public object Get(object obj);

   

   6:     public void Set(object obj, object value);

   

   7:

   

   8:     public static object Get(object obj, string propertyName);

   

   9:     public static void Set(object obj, string propertyName, object value);

   

  10:     //Others...

   

  11: }

如果预先知道了目标对象的类型,可能使用泛型的PropertyAccessor<T>会使操作更加方便。PropertyAccessor<T>继承自PropertyAccessor,定义如下:

   1: public class PropertyAccessor<T> : PropertyAccessor

   

   2: {

   

   3:     public PropertyAccessor(string propertyName);

   

   4:

   

   5:     public static object Get(T obj, string propertyName);

   

   6:     public static void Set(T obj, string propertyName, object value);

   

   7: }


二、如何通过PropertyAccessor获取属性值和为属性赋值

现在我们来演示如何通PropertyAccessor<T>来对目标对象的属性赋值,以及如何或者目标对象相应属性的值。现在我们定义如下一个实体类型:Contact。

   1: public class Contact

   

   2: {

   

   3:     public string       FirstName { get; set; }

   

   4:     public string       LastName { get; set; }

   

   5:     public string       Gender { get; set; }

   

   6:     public int?         Age { get; set; }

   

   7:     public DateTime?    Birthday { get; set; }

   

   8: }

然后我们在一个Console应用的Main方法中编写如下一段代码。在这段代码中,我创建了一个Contact对象,然后通过调用PropertyAccessor<Contact>类型的静态方法Set为该对象的各个属性进行复制。然后将各个属性值按照一定的格式打印出来,而获取属性值是通过调用静态方法Get完成的。

   1: static void Main(string[] args)

   

   2: {

   

   3:     var contact = new Contact();

   

   4:

   

   5:     PropertyAccessor<Contact>.Set(contact, "FirstName", "Jiang");

   

   6:     PropertyAccessor<Contact>.Set(contact, "LastName", "Jin Nan");

   

   7:     PropertyAccessor<Contact>.Set(contact, "Gender", "Male");

   

   8:     PropertyAccessor<Contact>.Set(contact, "Age", 30);

   

   9:     PropertyAccessor<Contact>.Set(contact, "Birthday", new DateTime(1981, 8, 24));

   

  10:

   

  11:     Console.WriteLine("Contact({0} {1})\n\tGender\t:{2}\n\tAge\t:{3}\n\tBirth\t:{4}",

   

  12:         PropertyAccessor<Contact>.Get(contact, "FirstName"),

   

  13:         PropertyAccessor<Contact>.Get(contact, "LastName"),

   

  14:         PropertyAccessor<Contact>.Get(contact, "Gender"),

   

  15:         PropertyAccessor<Contact>.Get(contact, "Age"),

   

  16:         PropertyAccessor<Contact>.Get(contact, "Birthday"));

   

  17: }

输出结果:

   1: Contact(Jiang Jin Nan)

   

   2:         Gender  :Male

   

   3:         Age     :30

   

   4:         Birth   :8/24/1981 12:00:00 AM


三、Set和Get的实现

虽然PropertyAccessor是一个很小的组件,但也不太可能将所有的代码列出来。在这里,我只是只能将核心部分作一下简单介绍,如果你想了解整个PropertyAccessor的实现,可以下载源代码。PropertyAccessor的两个核心的方法就是Get和Set。而在内部,它们对应着两个核心的方法:CreateGetFunction和CreateSetAction,它们利用IL Emit。下面是CreateGetFunction的实现:创建一个DynamicMethod对象,通过IL Emit调用属性的Getter方法,并将结果返回。最后通过DynamicMethod的CreateDelegate方法创建一个Func<object,object>委托对象并在本地缓存起来,供或许的获取属性值操作之用。

   1: private Func<object, object> CreateGetFunction()

   

   2: {

   

   3:      //...

   

   4:     DynamicMethod method = new DynamicMethod("GetValue", typeof(object), new Type[] { typeof(object) });

   

   5:     ILGenerator ilGenerator = method.GetILGenerator();

   

   6:     ilGenerator.DeclareLocal(typeof(object));

   

   7:     ilGenerator.Emit(OpCodes.Ldarg_0);

   

   8:     ilGenerator.Emit(OpCodes.Castclass, this.TargetType);

   

   9:     ilGenerator.EmitCall(OpCodes.Call, this.GetMethod, null);

   

  10:     if (this.GetMethod.ReturnType.IsValueType)

   

  11:     {

   

  12:         ilGenerator.Emit(OpCodes.Box, this.GetMethod.ReturnType);

   

  13:     }

   

  14:     ilGenerator.Emit(OpCodes.Stloc_0);

   

  15:     ilGenerator.Emit(OpCodes.Ldloc_0);

   

  16:     ilGenerator.Emit(OpCodes.Ret);

   

  17:

   

  18:     method.DefineParameter(1, ParameterAttributes.In, "value");

   

  19:     return (Func<object, object>)method.CreateDelegate(typeof(Func<object, object>));

   

  20: }

与CreateGetFunction类似,CreateSetAction同样创建一个DynamicMethod对象,通过IL Emit的方式调用属性的Setter方法。最后通过DynamicMethod的CreateDelegate方法创建一个Action<object,object>委托对象并在本地缓存起来,供后续的属性赋值操作之用。

   1: private Action<object, object> CreateSetAction()

   

   2: {

   

   3:     //...

   

   4:     DynamicMethod method = new DynamicMethod("SetValue", null, new Type[] { typeof(object), typeof(object) });

   

   5:     ILGenerator ilGenerator = method.GetILGenerator();

   

   6:     Type paramType = this.SetMethod.GetParameters()[0].ParameterType;

   

   7:     ilGenerator.DeclareLocal(paramType);

   

   8:     ilGenerator.Emit(OpCodes.Ldarg_0);

   

   9:     ilGenerator.Emit(OpCodes.Castclass, this.TargetType);

   

  10:     ilGenerator.Emit(OpCodes.Ldarg_1);

   

  11:     if (paramType.IsValueType)

   

  12:     {

   

  13:         ilGenerator.Emit(OpCodes.Unbox, paramType);

   

  14:         if (valueTpyeOpCodes.ContainsKey(paramType))

   

  15:         {

   

  16:             OpCode load = (OpCode)valueTpyeOpCodes[paramType];

   

  17:             ilGenerator.Emit(load);

   

  18:         }

   

  19:         else

   

  20:         {

   

  21:             ilGenerator.Emit(OpCodes.Ldobj, paramType);

   

  22:         }

   

  23:     }

   

  24:     else

   

  25:     {

   

  26:         ilGenerator.Emit(OpCodes.Castclass, paramType);

   

  27:     }

   

  28:

   

  29:     ilGenerator.EmitCall(OpCodes.Callvirt, this.SetMethod, null);

   

  30:     ilGenerator.Emit(OpCodes.Ret);

   

  31:

   

  32:     method.DefineParameter(1, ParameterAttributes.In, "obj");

   

  33:     method.DefineParameter(2, ParameterAttributes.In, "value");

   

  34:     return (Action<object, object>)method.CreateDelegate(typeof(Action<object, object>));

   

  35: }


四、比较三种属性操作的性能

我想大家最关心的还是“性能”的问题,现在我们就来编写一个性能测试的程序。在这个程序中我们比较三种典型的属性操作耗费的时间:直接通过属性赋值(或者取值)、通过IL Emit(即PropertyAccessor)和PropertyInfo对属性赋值(或者取值)。我们定义两个简单的类型Foo和Bar,Foo中定义一个类型和名称为Bar的可读写的属性。

   1: public class Foo

   

   2: {

   

   3:     public Bar Bar { get; set; }

   

   4: }

   

   5: public class Bar

   

   6: { }

下面是用于比较三种属性复制操作的测试程序SetTest,方法参数为复制操作的次数,最后将三种属性赋值操作的总时间(单位毫秒)分别打印出来。

   1: public static void SetTest(int times)

   

   2: {

   

   3:     Foo foo = new Foo();

   

   4:     Bar bar = new Bar();

   

   5:     Stopwatch stopwatch = new Stopwatch();

   

   6:     PropertyAccessor<Foo> propertyAccessor = new PropertyAccessor<Foo>("Bar");

   

   7:     PropertyInfo propertyInfo = typeof(Foo).GetProperty("Bar");

   

   8:     stopwatch.Start();

   

   9:     for (int i = 0; i < times; i++)

   

  10:     {

   

  11:         foo.Bar = bar;

   

  12:     }

   

  13:     long duration1 = stopwatch.ElapsedMilliseconds;

   

  14:

   

  15:     stopwatch.Restart();

   

  16:     for (int i = 0; i < times; i++)

   

  17:     {

   

  18:         propertyAccessor.Set(foo, bar);

   

  19:     }

   

  20:     long duration2 = stopwatch.ElapsedMilliseconds;

   

  21:

   

  22:     stopwatch.Restart();

   

  23:     for (int i = 0; i < times; i++)

   

  24:     {

   

  25:         propertyInfo.SetValue(foo, bar, null);

   

  26:     }

   

  27:     long duration3 = stopwatch.ElapsedMilliseconds;

   

  28:     Console.WriteLine("{0,-10}{1,-10}{2,-10}{3,-10}", times, duration1, duration2, duration3);

   

  29: }

下面是下面是用于比较三种或者属性值操作的测试程序GetTest,定义形式和上面一样:

   1: public static void GetTest(int times)

   

   2: {

   

   3:     Foo foo = new Foo { Bar = new Bar() };

   

   4:     Stopwatch stopwatch = new Stopwatch();

   

   5:     PropertyAccessor<Foo> propertyAccessor = new PropertyAccessor<Foo>("Bar");

   

   6:     PropertyInfo propertyInfo = typeof(Foo).GetProperty("Bar");

   

   7:     stopwatch.Start();

   

   8:     for (int i = 0; i < times; i++)

   

   9:     {

   

  10:         var bar = foo.Bar;

   

  11:     }

   

  12:     long duration1 = stopwatch.ElapsedMilliseconds;

   

  13:

   

  14:     stopwatch.Restart();

   

  15:     for (int i = 0; i < times; i++)

   

  16:     {

   

  17:         var bar = propertyAccessor.Get(foo);

   

  18:     }

   

  19:     long duration2 = stopwatch.ElapsedMilliseconds;

   

  20:

   

  21:     stopwatch.Restart();

   

  22:     for (int i = 0; i < times; i++)

   

  23:     {

   

  24:         var bar = propertyInfo.GetValue(foo, null);

   

  25:     }

   

  26:     long duration3 = stopwatch.ElapsedMilliseconds;

   

  27:     Console.WriteLine("{0,-10}{1,-10}{2,-10}{3,-10}", times, duration1, duration2, duration3);

   

  28: }

然后,我们在Console应用的Main方法中编写如下的代码,旨在测试次数分别为100000(十万)、1000000(一百万)和10000000(一千万)下三种不同形式的属性操作所耗用的时间。

   1: static void Main(string[] args)

   

   2: {

   

   3:     Console.WriteLine("{0,-10}{1,-10}{2,-10}{3,-10}", "Times", "General", "IL Emit", "Reflection");

   

   4:     SetTest(100000);

   

   5:     SetTest(1000000);

   

   6:     SetTest(10000000);

   

   7:

   

   8:     Console.WriteLine();

   

   9:     GetTest(100000);

   

  10:     GetTest(1000000);

   

  11:     GetTest(10000000);

   

  12: }

输出结果:

   1: Times     General   IL Emit   Reflection

   

   2: 100000    1         17        204

   

   3: 1000000   12        110       1918

   

   4: 10000000  131       1103      18919

   

   5:

   

   6: 100000    1         10        153

   

   7: 1000000   11        101       1534

   

   8: 10000000  112       1009      15425

由于我的笔记本已经差不多5年的历史,性能不是很好,所以更能反映出三种操作类型的性能差异。我们对属性直接进行赋值和取值是最快的,这一点没有什么好说的。我们关心的是,IL Emit的方式和单纯使用PropertyInfo进行反射(并且值得一提的是:PropertyInfo之前已经保存起来,并没有频繁去创建)的方式这两者的性能依然有本质的差别。如果你对数字不是敏感,那就看看下面的曲线图吧。

五、PropertyAccessor的ExpressionTree版本(2011-03-25)

对于很多人来说,IL Emit编程是一件很繁琐的事。反正我多这比较头疼,我一般的做法都是将需要的逻辑通过代码写出来,编译之后跟据IL写Emit代码。而我们更喜欢采用的则是ExpressionTree,为此我编写了PropertyAccessor的ExpressionTree版本(你可以从这里下载)。两个版本主要的不同还是在于上述两个方法:CreateGetFunction和CreateSetAction。下面是两个方法的定义:

   1: private Func<object, object> CreateGetFunction()

   

   2: {

   

   3:     var getMethod = this.Property.GetGetMethod();

   

   4:     var target = Expression.Parameter(typeof(object), "target");

   

   5:     var castedTarget = getMethod.IsStatic ? null : Expression.Convert(target, this.TargetType);

   

   6:     var getProperty = Expression.Property(castedTarget, this.Property);

   

   7:     var castPropertyValue = Expression.Convert(getProperty, typeof(object));

   

   8:     return Expression.Lambda<Func<object, object>>(castPropertyValue, target).Compile();

   

   9: }

   

  10:

   

  11: private Action<object, object> CreateSetAction()

   

  12: {

   

  13:     var setMethod = this.Property.GetSetMethod();

   

  14:     var target = Expression.Parameter(typeof(object), "target");

   

  15:     var propertyValue = Expression.Parameter(typeof(object), "value");

   

  16:     var castedTarget = setMethod.IsStatic ? null : Expression.Convert(target, this.TargetType);

   

  17:     var castedpropertyValue = Expression.Convert(propertyValue, this.PropertyType);

   

  18:     var propertySet = Expression.Call(castedTarget, setMethod, castedpropertyValue);

   

  19:     return Expression.Lambda<Action<object, object>>(propertySet, target, propertyValue).Compile();

   

  20: }

晚绑定场景下对象属性赋值和取值可以不需要PropertyInfo  
三种属性操作性能比较:PropertyInfo + Expression Tree + Delegate.CreateDelegate  
关于Expression Tree和IL Emit的所谓的"性能差别"

點(diǎn)擊查看更多內(nèi)容
TA 點(diǎn)贊

若覺(jué)得本文不錯(cuò),就分享一下吧!

評(píng)論

作者其他優(yōu)質(zhì)文章

正在加載中
  • 推薦
  • 評(píng)論
  • 收藏
  • 共同學(xué)習(xí),寫(xiě)下你的評(píng)論
感謝您的支持,我會(huì)繼續(xù)努力的~
掃碼打賞,你說(shuō)多少就多少
贊賞金額會(huì)直接到老師賬戶
支付方式
打開(kāi)微信掃一掃,即可進(jìn)行掃碼打賞哦
今天注冊(cè)有機(jī)會(huì)得

100積分直接送

付費(fèi)專欄免費(fèi)學(xué)

大額優(yōu)惠券免費(fèi)領(lǐng)

立即參與 放棄機(jī)會(huì)
微信客服

購(gòu)課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號(hào)

舉報(bào)

0/150
提交
取消