C # Another method of Expression Tree for copying objects quickly and efficiently,
1. Requirements
In the code, you often need to copy the object or copy the values with the same attribute name.
For example:
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 = 20, Id = 1, Name = "Emrys "};
We need to assign a value to the new Student.
Student ss = new Student {Age = s. Age, Id = s. Id, Name = s. Name };
Or assign a value to the attributes of another class StudentSecond. The names and types of the two class attributes are the same.
StudentSecond ss = new StudentSecond {Age = s. Age, Id = s. Id, Name = s. Name };
2. Solution
Of course, the most primitive method is to manually write all the attributes to be assigned values. This is the most efficient. However, the Code repetition rate is too high, and the Code does not look beautiful. More importantly, it is a waste of time. If a class has dozens of attributesOne by oneAttribute assignment is not a waste of energy. repetitive work like this should be optimized.
2.1 reflection
Reflection is a method that many people have used. It encapsulates a class, and reflection gets attributes and sets attribute values.
private static TOut TransReflection<TIn, TOut>(TIn tIn) { TOut tOut = Activator.CreateInstance<TOut>(); foreach (var itemOut in tOut.GetType().GetProperties()) { var itemIn = tIn.GetType().GetProperties().Where(i => i.Name == itemOut.Name).FirstOrDefault(); if (itemIn != null) { itemOut.SetValue(tOut, itemIn.GetValue(tIn)); } } return tOut; }
Call:StudentSecond ss = TransReflection <Student, StudentSecond> (s );
Call time: 1 million milliseconds
2.2 serialization
There are many serialization methods, such as binary, xml, and json. Today we will use Newtonsoft json for testing.
Call:StudentSecondSs= JsonConvert. DeserializeObject <StudentSecond> (JsonConvert. SerializeObject (s ));
Call time:2984 Ms
From this we can see that the serialization and reflection efficiency are not very different.
3. Expression Tree 3.1, Introduction
Baidu is not familiar with the expression tree.
That is to say, you can use the expression tree to copy objects.
Expression<Func<Student, StudentSecond>> ss = (x) => new StudentSecond { Age = x.Age, Id = x.Id, Name = x.Name }; var f = ss.Compile(); StudentSecond studentSecond = f(s);
In this way, we can achieve the same effect.
Some people say that this writing method is no different from the original copy method, but the code is getting more. This is only the first step.
3.2 analyze code
We use ILSpy to decompile the code of this expression as follows:
ParameterExpression parameterExpression; Expression<Func<Student, StudentSecond>> ss = Expression.Lambda<Func<Student, StudentSecond>>(Expression.MemberInit(Expression.New(typeof(StudentSecond)), new MemberBinding[] { 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()))) }), new ParameterExpression[] { parameterExpression }); Func<Student, StudentSecond> f = ss.Compile(); StudentSecond studentSecond = f(s);
So we only need to useReflection loops all attributes and then Expression. Bind all attributes. Finally, call Compile () (s) to obtain the correct StudentSecond.
If reflection is used, isn't it very efficient? Is there any difference between reflection and serialization?
Of course, what this can solve is that our expression tree canCache. Only reflection is required for the first time, and reflection is not required for later use.
3.3 copy Common Object Code
For the sake of universality, Student and StudentSecond are replaced with generics respectively.
private static Dictionary<string, object> _Dic = new Dictionary<string, object>(); private static TOut TransExp<TIn, TOut>(TIn tIn) { string key = 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 = new List<MemberBinding>(); foreach (var item in typeof(TOut).GetProperties()) { 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, new ParameterExpression[] { 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 time: 1 millionMillisecond
4. Summary
From the above tests and analysis, we can easily conclude that the expression tree can be used to achieveEfficiencyAndWriting MethodBoth methodsOne,In short, it is better than traditional serialization and reflection.
I hope it will be helpful to you. This article is original and you are welcome to make a brick andRecommendation.