• 扩展IList对象,实现深拷贝扩展方法


    扩展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

    原文地址:http://www.cnblogs.com/qiuliang/archive/2012/02/29/2373671.html

  • 相关阅读:
    2018年12月9日 带小苗苗打针 函数2 前向引用 函数即变量
    2018年12月8日 函数变量与递归
    2018年12月7日 字符串格式化2 format与函数1
    2018年12月6日 字符串拼接 %的用法
    2018年11月29日 16点50分 小苗苗出生了
    2018年11月27日 分类与集合
    2018年11月26日 练习3
    2018年11月25日 练习2
    2018年11月24日 周末学习1 字典2
    2018年11月22日 字典 E18灯翼平整度 D&G is SB
  • 原文地址:https://www.cnblogs.com/suizhikuo/p/2375387.html
Copyright © 2020-2023  润新知