




版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第C#深拷貝方法探究及性能比較(多種深拷貝)目錄1、手寫(xiě)創(chuàng)建對(duì)象2、反射3、Json字符串序列化4、對(duì)象二進(jìn)制序列化5、AutoMapper6、表達(dá)式樹(shù)之前學(xué)習(xí)了設(shè)計(jì)模式原型模式,在原型模式中就提到了對(duì)象的深拷貝。深拷貝指的是拷貝一個(gè)對(duì)象時(shí),不僅僅把對(duì)象的引用進(jìn)行復(fù)制,還把該對(duì)象引用的值也一起拷貝。與淺拷貝不同的就是,深拷貝后的拷貝對(duì)象就和源對(duì)象互相獨(dú)立,其中任何一個(gè)對(duì)象的改動(dòng)都不會(huì)對(duì)另外一個(gè)對(duì)象造成影響。
在查詢(xún)資料之后,探究了以下幾種C#對(duì)象深拷貝方式,同時(shí)簡(jiǎn)單對(duì)比了以下列出的幾種深拷貝方式的速度(簡(jiǎn)單測(cè)試,僅測(cè)試對(duì)象深拷貝速度,不考慮性能影響)。
測(cè)試平臺(tái):Intel9700K+DDR4360032G,框架為.NET5.0。測(cè)試方式為創(chuàng)建100萬(wàn)次,比較執(zhí)行時(shí)間。拷貝的對(duì)象如下:
[Serializable]
classUserInfo
publicstringName{get;set;}
publicstringUserId{get;set;}
publicintAge{get;set;}
publicstringAddress{get;set;}
publiclongUpdateTime{get;set;}
publiclongCreateTime{get;set;}
}
1、手寫(xiě)創(chuàng)建對(duì)象
簡(jiǎn)單對(duì)象創(chuàng)建,不考慮有構(gòu)造函數(shù)的情況。
NewUserInfonewInfo=newNewUserInfo()
Name=info.Name,
Age=info.Age,
UserId=info.UserId,
Address=info.Address,
UpdateTime=info.UpdateTime,
CreateTime=info.CreateTime,
};
100萬(wàn)次執(zhí)行時(shí)間為39.4073ms,位居第一。當(dāng)然,在這種不考慮構(gòu)造函數(shù)的情況下,手寫(xiě)創(chuàng)建肯定是最快的。但是同時(shí),如果遇到復(fù)雜對(duì)象,代碼量也是最多的。
2、反射
這也是在日常代碼中最常用的方式之一。
privatestaticTOutTransReflectionTIn,TOut(TIntIn)
TOuttOut=Activator.CreateInstanceTOut
vartInType=tIn.GetType();
foreach(varitemOutintOut.GetType().GetProperties())
varitemIn=tInType.GetProperty(itemOut.Name);;
if(itemIn!=null)
itemOut.SetValue(tOut,itemIn.GetValue(tIn));
returntOut;
}
調(diào)用
NewUserInfonewInfo=TransReflectionUserInfo,NewUserInfo(info);
100萬(wàn)次執(zhí)行時(shí)間為1618.4662ms,平均執(zhí)行時(shí)間為0.001618,看起來(lái)還行。
3、Json字符串序列化
使用System.Text.Json作為序列化和反序列化工具。
UserInfonewInfo=JsonSerializer.DeserializeUserInfo(JsonSerializer.Serialize(info));
100萬(wàn)次執(zhí)行時(shí)間為2222.2078ms,比反射慢一點(diǎn)點(diǎn)。
4、對(duì)象二進(jìn)制序列化
首先不推薦使用這種方式,一是BinaryFormatter.Serialize微軟已不推薦使用(據(jù)微軟官網(wǎng)文檔說(shuō)是有漏洞,具體有什么漏洞沒(méi)細(xì)究),二是必須在要序列化的對(duì)象上面寫(xiě)上Serializable的關(guān)鍵字,三是速度并不理想。
privatestaticTOutObjectMemoryConvertTIn,TOut(TIntIn)
using(MemoryStreamms=newMemoryStream())
BinaryFormatterformatter=newBinaryFormatter();
formatter.Serialize(ms,tIn);
ms.Position=0;
return(TOut)formatter.Deserialize(ms);
}
100萬(wàn)次執(zhí)行時(shí)間為8545.9835ms,講道理應(yīng)該是比Json序列化要更快的,但是實(shí)際上慢了許多。
5、AutoMapper
熟悉的AutoMapper,性能也沒(méi)有讓我們失望。
//循環(huán)外創(chuàng)建MapperConfig
varconfig=newMapperConfiguration(cfg=cfg.CreateMapUserInfo,UserInfo
varmapper=config.CreateMapper();
//循環(huán)內(nèi)調(diào)用
UserInfonewInfo=mapper.MapUserInfo(info);
100萬(wàn)次執(zhí)行時(shí)間為267.5073ms,位居第三。
6、表達(dá)式樹(shù)
重頭戲來(lái)了,此處代碼來(lái)源于文首中的博客中,性能讓人大吃一驚。其原理是反射和表達(dá)式樹(shù)相結(jié)合,先用反射獲取字段然后緩存起來(lái),再用表達(dá)式樹(shù)賦值。
publicstaticclassTransExpTIn,TOut
privatestaticreadonlyFuncTIn,TOutcache=GetFunc();
privatestaticFuncTIn,TOutGetFunc()
ParameterExpressionparameterExpression=Expression.Parameter(typeof(TIn),"p");
ListMemberBindingmemberBindingList=newListMemberBinding
foreach(varitemintypeof(TOut).GetProperties())
if(!item.CanWrite)continue;
MemberExpressionproperty=Expression.Property(parameterExpression,typeof(TIn).GetProperty(item.Name));
MemberBindingmemberBinding=Expression.Bind(item,property);
memberBindingList.Add(memberBinding);
MemberInitExpressionmemberInitExpression=Expression.MemberInit(Expression.New(typeof(TOut)),memberBindingList.ToArray());
ExpressionFuncTIn,TOutlambda=Expression.LambdaFuncTIn,TOut(memberInitExpression,newParameterExpression[]{parameterExpression});
returnlambda.Compile();
publicstaticTOutTrans(TIntIn)
returncache(tIn);
}
調(diào)用
UserInfonewInfo=TransExpUserInfo,UserInfo.Trans(info);
100萬(wàn)次執(zhí)行時(shí)間為77.3653ms,位居第二。僅比手寫(xiě)慢一點(diǎn)點(diǎn)。
簡(jiǎn)單整理成柱狀圖,可以很清晰的對(duì)比出這幾種深拷貝方式之間的速度差距。總結(jié)來(lái)說(shuō)就是,一般簡(jiǎn)單的對(duì)象深拷貝,推薦直接手寫(xiě),復(fù)雜對(duì)象深拷貝,推薦使用表達(dá)式樹(shù)。當(dāng)然,如果創(chuàng)建對(duì)象中還涉及到構(gòu)造函數(shù)初始化,那又是不同的情況,這里暫不討論。
附上本次測(cè)試用的完整代碼。
usingAutoMapper;
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Diagnostics;
usingSystem.IO;
usingSystem.Linq.Expressions;
usingSystem.Runtime.Serialization;
usingSystem.Runtime.Serialization.Formatters.Binary;
usingSystem.Text.Json;
usingSystem.Threading.Tasks;
namespaceTestObjectDeepCopy
classProgram
staticvoidMain(string[]args)
UserInfoinfo=newUserInfo()
Name="張三",
Age=18,
UserId=Guid.NewGuid().ToString("N"),
Address="銀河系地球中國(guó)",
UpdateTime=1615888888,
CreateTime=1615895454,
varconfig=newMapperConfiguration(cfg=cfg.CreateMapUserInfo,UserInfo
varmapper=config.CreateMapper();
intcount=1000000;
Stopwatchsw=newStopwatch();
sw.Start();
for(inti=-0;icount;i++)
//手寫(xiě)39.4073ms
//UserInfonewInfo=newUserInfo()
//Name=info.Name,
//Age=info.Age,
//UserId=info.UserId,
//Address=info.Address,
//UpdateTime=info.UpdateTime,
//CreateTime=info.CreateTime,
//};
//反射1618.4662ms
//UserInfonewInfo=TransReflectionUserInfo,UserInfo(info);
//Json字符串序列化2222.2078ms
//UserInfonewInfo=JsonSerializer.DeserializeUserInfo(JsonSerializer.Serialize(info));
//對(duì)象二進(jìn)制序列化8545.9835ms
//UserInfonewInfo=ObjectMemoryConvertUserInfo,UserInfo(info);
//表達(dá)式樹(shù)77.3653ms
//UserInfonewInfo=TransExpUserInfo,UserInfo.Trans(info);
//AutoMapper267.5073ms
//UserInfonewInfo=mapper.MapUserInfo(info);
Console.WriteLine("總共花費(fèi){0}ms.",sw.Elapsed.TotalMilliseconds);
sw.Stop();
Console.ReadKey();
privatestaticTOutTransReflectionTIn,TOut(TIntIn)
TOuttOut=Activator.CreateInstanceTOut
vartInType=tIn.GetType();
foreach(varitemOutintOut.GetType().GetProperties())
varitemIn=tInType.GetProperty(itemOut.Name);;
if(itemIn!=null)
itemOut.SetValue(tOut,itemIn.GetValue(tIn));
returntOut;
privatestaticTOutObjectMemoryConvertTIn,TOut(TIntIn)
using(MemoryStreamms=newMemoryStream())
BinaryFormatterformatter=newBinaryFormatter();
formatter.Serialize(ms,tIn);
ms.Position=0;
return(TOut)formatter.Deserialize(ms);
publicstaticclassTransExpTIn,TOut
privatestaticreadonlyFuncTIn,TOutcache=GetFunc();
privatestaticFuncTIn,TOutGetFunc()
ParameterExpressionparameterExpression=Expression.Parameter(typeof(TIn),"p");
ListMemberBindingmemberBindingList=newListMemberBinding
foreach(varitemintypeof(TOut).GetProperties())
if(!item.CanWrite)continue;
MemberExpressionproperty=Expression.Property(parameterExpression,typeof(TIn).GetProperty(item.Name));
MemberBindingmemberBindin
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025暫緩就業(yè)協(xié)議書(shū)
- 特殊兒童安全管理協(xié)議書(shū)
- 消防設(shè)施檢測(cè)合同范本
- 超市蔬菜承包合同范本
- 電站轉(zhuǎn)讓合同協(xié)議書(shū)模板
- 購(gòu)買(mǎi)住宅底商合同范本
- 餐廳經(jīng)營(yíng)合伙合同范本
- 照顧小孩保姆合同范本
- 自由教練合作合同范本
- 2025年地理信息技術(shù)在初中地理教學(xué)中的實(shí)踐應(yīng)用模擬試卷及答案解析
- 《實(shí)驗(yàn):基于醫(yī)療大數(shù)據(jù)的心血管疾病預(yù)測(cè)與干預(yù)》
- 化學(xué)錨栓埋件的計(jì)算(形式三)
- 六年級(jí)語(yǔ)文非連續(xù)性文本專(zhuān)項(xiàng)訓(xùn)練
- 新時(shí)代高職英語(yǔ)(基礎(chǔ)模塊)Unit7
- 泵的選型原則、依據(jù)及步驟
- GB/T 15114-2023鋁合金壓鑄件
- 2023-2024學(xué)年安徽省銅陵市小學(xué)語(yǔ)文六年級(jí)期末自測(cè)試卷附參考答案和詳細(xì)解析
- 八年級(jí)物理下冊(cè)《十一、十二章》階段測(cè)試卷及答案(人教版)
- 丹東地方方言
- “胡不歸”模型探究 說(shuō)課課件
- 羅斯公司理財(cái)Chap003全英文題庫(kù)及答案
評(píng)論
0/150
提交評(píng)論