Go How to quickly and efficiently replicate objects in C #

Source: Internet
Author: User

1. Demand

It is often necessary to copy objects into a new object in the project code, or to copy the values of the same property names once.

Like what:

    public class Student    {public        int Id {get; set;}        public string Name {get; set;}         public int Age {get; set;}     }    public class Studentsecond    {public        int Id {get; set;}        public string Name {get; set;}        public int Age {get; set;}     }

Student s = new Student () {age = $, Id = 1, Name = "Emrys"};

We need to assign a new student.

Student ss = new Student {age = s.age, Id = s.id, Name = s.name};

Assigns a value to the property of another class Studentsecond, with the names and types of the two class properties consistent.

Studentsecond ss = new Studentsecond {age = s.age, Id = s.id, Name = s.name};

2. Solutions

The most primitive approach, of course, is to manually hand-write all properties that need to be assigned. This is the highest efficiency. However, the repetition rate of the code is too high, more important is a waste of time, if a class has dozens of attributes, that one property assignment is too wasteful, like this duplication of work should be more need to optimize.

2.1. Reflection

Reflection should be a method used by many people, that is, encapsulating a class, reflecting the Get property and setting the value of the property.

Private StaticTOut Transreflection<tin, tout>(Tin Tin) {TOut TOut= activator.createinstance<tout>(); varTintype =Tin.gettype (); foreach(varItemoutinchTout.gettype (). GetProperties ()) {varItemIn =Tintype.getproperty (itemout.name); if(ItemIn! =NULL) {Itemout.setvalue (TOut, Itemin.getvalue (tIn)); }            }            returnTOut; }

Call:studentsecond ss= transreflection<student, studentsecond> (s);

Call 1 million times time: 2464 milliseconds

2.2. Serialization

There are many ways to serialize, with binary, XML, JSON, and so on, and today we're testing with newtonsoft json.

Call:studentsecond ss= jsonconvert.deserializeobject<studentsecond> ( Jsonconvert.serializeobject (s));

call 1 million times time:2984 milliseconds

3. Expression Tree 3.1, Introduction

About the expression tree do not understand can Baidu.

This means that copying objects can also be used in the expression tree

New Studentsecond {age = x.age, Id = x.id, Name = x.name};         var f = ss.compile ();         = f (s);

In this way we can achieve the same effect. It seems that there is no difference between this and the original copy, but the code is much more, but this is only the first step. Follow!!!!!!!!!!!!!!!!!!!!!!!.

3.2. Analysis Code

Use Ilspy to decompile This expression code as follows:

parameterexpression parameterexpression; Expression<func<student, studentsecond>> ss = Expression.lambda<func<student, StudentSecond>> ( Expression.memberinit (Expression.new (typeof(Studentsecond)),Newmemberbinding[] {expression.bind (Methodof (Studentsecond.set_age (int) , Expression.property (ParameterExpression, Methodof (Student.get_age ())), Expression.bind (Methodof ( STUDENTSECOND.SET_ID (int) , Expression.property (ParameterExpression, Methodof (student.get_id ())), Expression.bind (Methodof ( Studentsecond.set_name (string)) , Expression.property (ParameterExpression, Methodof (Student.get_name () ))),Newparameterexpression[] {parameterexpression}); Func<student, studentsecond> f =Ss.compile (); Studentsecond Studentsecond= f (s);

Just loop all the properties with reflection and then expression.bind all the properties . Finally call compile () (s) to get the correct studentsecond.

Some people have to ask again, if the reflection is not very inefficient, and direct use of reflection or serialization with no difference?

Of course this can be solved, is that our expression tree can be cached . It's just a reflection when you use it for the first time, and you don't need to reflect it later.

3.3. Copy object Generic Code

For versatility, the student and Studentsecond are replaced by generics respectively.

Private Staticdictionary<string,Object> _dic =Newdictionary<string,Object>(); Private StaticTOut Transexp<tin, tout>(Tin Tin) {stringKey =string. Format ("Trans_exp_{0}_{1}",typeof(TIn). FullName,typeof(TOut).            FullName); if(!_dic.containskey (Key)) {parameterexpression parameterexpression= Expression.parameter (typeof(TIn),"P"); List<MemberBinding> memberbindinglist =NewList<memberbinding>(); foreach(varIteminch typeof(TOut). GetProperties ()) {if(!item. CanWrite)Continue; Memberexpression Property= Expression.property (ParameterExpression,typeof(TIn). GetProperty (item.                    Name)); Memberbinding memberbinding=Expression.bind (item, property);                Memberbindinglist.add (memberbinding); } memberinitexpression memberinitexpression= Expression.memberinit (Expression.new (typeof(TOut)), Memberbindinglist.toarray ()); Expression<func<tin, tout>> lambda = expression.lambda<func<tin, tout>> (Memberinitexpression,Newparameterexpression[] {parameterexpression}); Func<tin, tout> func =Lambda.compile (); _dic[key]=func; }            return(Func<tin, tout>) _dic[key]) (tIn); }

Call:studentsecond ss= transexp<student, studentsecond> (s);

call 1 million times time: 564 milliseconds

3.4. Re-optimize the code with generic features

Store the cache without a dictionary, because generics can easily solve this problem.

 Public Static classTransexpv2<tin, tout>    {        Private Static ReadOnlyFunc<tin, tout> cache =Getfunc (); Private StaticFunc<tin, tout>Getfunc () {parameterexpression parameterexpression= Expression.parameter (typeof(TIn),"P"); List<MemberBinding> memberbindinglist =NewList<memberbinding>(); foreach(varIteminch typeof(TOut). GetProperties ()) {if(!item. CanWrite)Continue; Memberexpression Property= Expression.property (ParameterExpression,typeof(TIn). GetProperty (item.                Name)); Memberbinding memberbinding=Expression.bind (item, property);            Memberbindinglist.add (memberbinding); } memberinitexpression memberinitexpression= Expression.memberinit (Expression.new (typeof(TOut)), Memberbindinglist.toarray ()); Expression<func<tin, tout>> lambda = expression.lambda<func<tin, tout>> (Memberinitexpression,Newparameterexpression[] {parameterexpression}); returnLambda.compile (); }         Public StaticTOut Trans (Tin Tin) {returncache (tIn); }    }

Call:studentsecond ss= transexpv2<student, Studentsecond>. Trans (s);

call 1 million times time: 107 milliseconds

It takes far less than 338 milliseconds to use AutoMapper.

4. Summary

From the above test and analysis can be easily concluded that the expression tree is a way to achieve both efficiency and writing methods , in short, than the traditional serialization and reflection more excellent.

The last hope is helpful to you.

Reference point: http://www.cnblogs.com/emrys5/

Go How to quickly and efficiently replicate objects in C #

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.