.Net 記一次實體類拷貝效率測試

測試背景(更詳細介紹,請參照這篇文章,感謝樓主無私奉獻):

有時候爲了將實體的字段值賦值給DTO的字段,需要實現複製功能(字段較多的時候,直接硬編碼會很痛苦)。一般可以通過硬編碼、反射、序列化反序列化實現,但效率都相對較低。今天我們通過表達式樹的方式,實現複製功能,順便和序列化反序列化方法做個性能比對。

DTO:數據傳輸對象,我們經常用到的一個東西。有時候我們稱之爲的ViewModel也屬於其中之一。以往,我們總是複製實體類型的一些字段 然後單獨創建這些對象。

實體類如下:

    public class Person
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

DTO如下:

    public class PersonDTO
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

序列化反序列化如下:

 using Newtonsoft.Json;
 public static class ObjectExtension
    {
        /// <summary>
        /// 序列化、反序列化
        /// </summary>
        /// <typeparam name="TIn"></typeparam>
        /// <typeparam name="TOut"></typeparam>
        /// <param name="t"></param>
        /// <returns></returns>
        public static TOut Copy<TIn, TOut>(TIn t)
        {
            return JsonConvert.DeserializeObject<TOut>(JsonConvert.SerializeObject(t));
        }

    }

表達式目錄樹如下:

    using System.Linq.Expressions;
    using System.Runtime.Serialization.Formatters.Binary;

    /// <summary>
    /// 表達式目錄樹 拷貝方法,必須是同結構類
    /// </summary>
    /// <typeparam name="TIn"></typeparam>
    /// <typeparam name="TOut"></typeparam>
    public class ExpressionGenercMapper<TIn, TOut>
    {
        private static Func<TIn, TOut> _Func = null;
        static ExpressionGenercMapper()
        {
            ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");
            List<MemberBinding> memberBindings = 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);
                memberBindings.Add(memberBinding);
            }
            foreach (var item in typeof(TOut).GetFields())
            {
                MemberExpression property = Expression.Field(parameterExpression, typeof(TIn).GetField(item.Name));
                MemberBinding memberBinding = Expression.Bind(item, property);
                memberBindings.Add(memberBinding);
            }
            MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindings.ToArray());
            Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[]
            {
                    parameterExpression
            });
            _Func = lambda.Compile();
        }

        public static TOut Trans(TIn t)
        {
            return _Func(t);
        }

    }

測試如下:

Person person = new Person()
            {
                Id = 1,
                Name = "張三"
            };

            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            for (int i = 0; i < 100_000; i++)
            {
                PersonDTO personClone = ObjectExtension.Copy<Person, PersonDTO>(person);
            }
            stopwatch.Stop();
            TimeSpan timespan = stopwatch.Elapsed;
            double millisecondsOne = timespan.TotalMilliseconds;

            Stopwatch stopwatch1 = new Stopwatch();
            stopwatch1.Start();
            for (int i = 0; i < 100_000; i++)
            {
                PersonDTO personClone = ExpressionGenercMapper<Person, PersonDTO>.Trans(person);
            }
            stopwatch1.Stop();
            TimeSpan timespan1 = stopwatch1.Elapsed;
            double millisecondsTwo = timespan1.TotalMilliseconds;
            Console.WriteLine($"序列化:{millisecondsOne}s");
            Console.WriteLine($"目錄樹:{millisecondsTwo}s");

結果如下:

結論:

通過上面的測試可以看出,兩者行能相差較大,表達式目錄樹更適合做數據複製。

謝謝打賞

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章