zoukankan      html  css  js  c++  java
  • 【转载】对象克隆(C# 快速高效率复制对象另一种方式 表达式树转)

    Linqpad 代码

    Benmarker测试结果耗时改善很明显,而且还可以支持深度复制,看来果然很优秀

    // * Summary *

    BenchmarkDotNet=v0.12.0, OS=Windows 10.0.18362
    Intel Core i7-9700 CPU 3.00GHz, 1 CPU, 8 logical and 8 physical cores
    .NET Core SDK=3.1.201
      [Host] : .NET Core 3.1.3 (CoreCLR 4.700.20.11803, CoreFX 4.700.20.12001), X64 RyuJIT


    |              Method |           Mean |         Error |      StdDev |
    |
    -------------------- |---------------:|--------------:|------------:|
    | TestTransReflection |   1,204.881 ns |    23.2975 ns |  23.9248 ns |
    |      TestExpression | 122,195.921 ns | 1,007.6728 ns | 942.5777 ns |
    |        TestTransExp |     250.915 ns |     2.1132 ns |   1.9767 ns |
    |      TestTransExpV2 |       9.475 ns |     0.2525 ns |   0.2362 ns |
    |       TestAutoMappe |     176.756 ns |     3.5712 ns |   3.6673 ns |
    <Query Kind="Program">
      <Reference Relative="....LibsAutoMapper.9.0.0lib
    etstandard2.0AutoMapper.dll">D:projectsgithubsui84linqpadLINQPad QueriesLibsAutoMapper.9.0.0lib
    etstandard2.0AutoMapper.dll</Reference>
      <NuGetReference>BenchmarkDotNet</NuGetReference>
      <Namespace>AutoMapper</Namespace>
      <Namespace>BenchmarkDotNet.Attributes</Namespace>
      <Namespace>BenchmarkDotNet.Running</Namespace>
      <Namespace>System.Security.Cryptography</Namespace>
      <Namespace>System.Windows.Forms.DataVisualization.Charting</Namespace>
    </Query>
    
    #LINQPad optimize+
    /*
    
    对象克隆(C# 快速高效率复制对象另一种方式 表达式树转) 
    https://www.cnblogs.com/lsgsanxiao/p/8205096.html
    */
    
    void Main()
    {
        Student s = InitStudent();
    	//StudentSecond ss= TransReflection<Student, StudentSecond>(s);
    	StudentSecond ss= TransExpV2<Student, StudentSecond>.Trans(s);
    	ss.Dump();
    	
    	var summary = BenchmarkRunner.Run<CloneBenchmarks>();
    	 
    }
    
    public static Student InitStudent(){
    	List<Address> studentAddress = new List<Address>();
    	studentAddress.Add(new Address(){address="testaddress1"});
    	studentAddress.Add(new Address(){address="testaddress2"});
        Student s = new Student() { Age = 20, Id = 1, Name = "Emrys" , StudentAddress = studentAddress};
    	return s;
    }
    
    public class Student
    {
        public int Id { get; set; }
        public string Name { get; set; } 
        public int Age { get; set; } 
    	public List<Address> StudentAddress { get; set; } 
    }
    
    public class StudentSecond
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Age { get; set; } 
    	public List<Address> StudentAddress { get; set; } 
    }
    
    public class Address 
    { 
        public string address { get; set; } 
    } 
    
    
    public class CloneBenchmarks
    {
    	AutoMapper.IMapper _mapper;
    	Student _s;
    	public CloneBenchmarks(){
    	 	var config = new MapperConfiguration(cfg => {
    	    cfg.CreateMap<Student, StudentSecond>();
    	    cfg.CreateMap<Address, Address>();
    		});
    		config.AssertConfigurationIsValid();
    		_mapper = config.CreateMapper();
    		 _s = InitStudent();
    	}
    
    	[Benchmark]
    	public object TestTransReflection(){
    		StudentSecond ss= TransReflection<Student, StudentSecond>(_s);
    		return ss;
    	}
    	
    	[Benchmark]
    	public object TestExpression(){
    		Expression<Func<Student, StudentSecond>> ss = (x) => new StudentSecond { Age = x.Age, Id = x.Id, Name = x.Name , StudentAddress = x.StudentAddress };
            var f = ss.Compile();
            StudentSecond studentSecond = f(_s);
    		return studentSecond;
    	}
    	
    	private static Dictionary<string, object> _Dic = new Dictionary<string, object>();
    
    
    	[Benchmark]
    	public object TestTransExp(){
    		StudentSecond ss= TransExp<Student, StudentSecond>(_s);
    		return ss;
    	}
    	
    	[Benchmark]
    	public object TestTransExpV2(){
    		StudentSecond ss= TransExpV2<Student, StudentSecond>.Trans(_s);
    		return ss;
    	}
    	
    	[Benchmark]
    	public object TestAutoMappe(){
    		var ss = _mapper.Map<Student, StudentSecond>(_s);
    		return ss;
     	}
    	
    	public  TOut TransReflection<TIn, TOut>(TIn tIn)
    	{
    	    TOut tOut = Activator.CreateInstance<TOut>();
    	    var tInType = tIn.GetType();
    	    foreach (var itemOut in tOut.GetType().GetProperties())
    	    {
    	        var itemIn = tInType.GetProperty(itemOut.Name); ;
    	        if (itemIn != null)
    	        {
    	            itemOut.SetValue(tOut, itemIn.GetValue(tIn));
    	        }
    	    }
    	    return tOut;
    	}
    	
       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())
                {  
    
    				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, new ParameterExpression[] { parameterExpression });
                Func<TIn, TOut> func = lambda.Compile();
    
                _Dic[key] = func;
            }
            return ((Func<TIn, TOut>)_Dic[key])(tIn);
        }
    	
    
    
    }
    
    public static class TransExpV2<TIn, TOut>
    {
    
        private static readonly Func<TIn, TOut> cache = GetFunc();
        private static Func<TIn, TOut> GetFunc()
        {
            ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");
            List<MemberBinding> memberBindingList = new List<MemberBinding>();
    
            foreach (var item in 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, new ParameterExpression[] { parameterExpression });
    
            return lambda.Compile();
        }
    	
    	public static TOut Trans(TIn tIn)
        {
            return cache(tIn);
        }
    }
    

      

  • 相关阅读:
    十四、内存泄露和强软弱虚引用
    十五、对象的内存布局
    Android Service全解(三)之 Foreground Service(转)
    android中不同activity的传参调用和返回
    Android Service全解(一)之 startService(转)
    Android Service全解(二)之 bindService(转)
    android单点、多点触控之MotionEvent
    关于创建进程函数CreateProcess()字符串参数的说明
    sql中连接两个不同的数据库(A在同一个服务器,B不在一个服务器)
    asp.net小数点四舍五入的方法
  • 原文地址:https://www.cnblogs.com/sui84/p/12815283.html
Copyright © 2011-2022 走看看