擴展IList對象,實現深拷貝擴展方法


應用場景

對一個集合進行深拷貝復制,實現的方法有不少,現舉一個常規實現方案:例如已有一個List<T> someList

List<T> newList = new List<T>();
foreach(var item in someList)
{
T t = new T();
//此處的屬性如果是引用類型,還需要考慮該類型的深拷貝實現
t.P1 = item.P1;
t.P2 = item.P2;
     ...
newList.Add(t);
}

如果類似的需求不止一個,那我們就要反復書寫類似的代碼,這顯然不符合代碼重用的原則。

思路

首先想到的應該是擴展方法,並且是基於泛型的擴展方法,這個簡單,上代碼:

public static IList<T> Clone<T>(this IList<T> source)
{
IList<T> newList = new List<T>(source.Count);
foreach (var item in source)
{
newList.Add(..);
}
return newList;
}

這個add方法里還是要new一個T對象,並且挨個給屬性賦值,那豈不是也很麻煩,這時候肯定有同學想到了反射,對,使用反射可以解決這個問題,但我認為還不是很理想。

第二次思考。。。對了,微軟不是已經為我們提供了一個接口叫ICloneable的么?我們應該為T加上約束,修改代碼如下:

public static IList<T> Clone<T>(this IList<T> source)
where T : ICloneable
{
IList<T> newList = new List<T>(source.Count);
foreach (var item in source)
{
newList.Add((T)((ICloneable)item.Clone()));
}
return newList;
}

現在看上去還不錯了,基本思路已經成型,在調用的時候可以這樣使用: newList = someList.Clone();

當然,別忘了給你的T加上ICloneable接口,並實現Clone方法,實現Clone的方法有很多,個人建議如下:

        public object Clone()
{
MemoryStream stream = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, this);
stream.Position = 0;
var obj = formatter.Deserialize(stream) as Class;
return obj;
}

使用序列化的方式進行對象的復制,這樣做的前提是你的Class需要被標記為Serializable。

使用EF時碰到的實際案例

例如一個Entity有很多關聯的實體(主子表),現在需要復制原始記錄作為一份全新的記錄,包括所有的子表,如果采用常規方法,做起來是會很繁瑣的,需要挨個遍歷子表集合,並new一個全新的實體對象,再挨個執行AddObject,如果采用上面的方案,代碼如下:

//子表集合
var resList = this.ResourcePlanService.GetList(t => t.QuoteID == quoteId).ToList();
ForeachCopy(resList, this.ResourcePlanService);

private void ForeachCopy<TModel, TService>(IList<TModel> list, TService service)
where TService : IService<TModel>
where TModel : ICloneable
{

list.Clone().ForEach( t => service.Add(t) );

}

這樣代碼就精簡了很多,對原來的改動也相對較小,只需要把TModel的基類EntityObjectBase實現ICloneable接口,並實現Clone方法即可,需要注意的是,如果EF采用DB First方式,則需要在Clone方法里面把EntityKey設置為null,否則,在調用AddObject的時候,ObjectManagement會拋出異常。

總結

 優點:代碼簡單、復用度高
       缺點:需要修改類對象以繼承ICloneable接口,如果沒有基類的話,也是一個很麻煩的問題,並且類對象需要被標記為Serializable


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM