without - copiar datos de una lista a otra en c#



¿Cómo puedo clonar una lista genérica en C#? (16)

A menos que necesite un clon real de cada objeto dentro de su List<T> , la mejor manera de clonar una lista es crear una nueva lista con la lista antigua como parámetro de colección.

List<T> myList = ...;
List<T> cloneOfMyList = new List<T>(myList);

Los cambios en myList , como insertar o eliminar, no afectarán a cloneOfMyList y viceversa.

Sin embargo, los objetos reales que contienen las dos listas siguen siendo los mismos.

https://code.i-harness.com

Tengo una lista genérica de objetos en C #, y deseo clonar la lista. Los elementos de la lista se pueden clonar, pero no parece haber una opción para hacer list.Clone() .

¿Hay una manera fácil de evitar esto?


Después de una ligera modificación también puedes clonar:

public static T DeepClone<T>(T obj)
{
    T objResult;
    using (MemoryStream ms = new MemoryStream())
    {
        BinaryFormatter bf = new BinaryFormatter();
        bf.Serialize(ms, obj);
        ms.Position = 0;
        objResult = (T)bf.Deserialize(ms);
    }
    return objResult;
}

Hay una forma sencilla de clonar objetos en C # utilizando un serializador JSON y deserializador.

Puedes crear una clase de extensión:

using Newtonsoft.Json;

static class typeExtensions
{
    [Extension()]
    public static T jsonCloneObject<T>(T source)
    {
    string json = JsonConvert.SerializeObject(source);
    return JsonConvert.DeserializeObject<T>(json);
    }
}

Para clonar y objetar:

obj clonedObj = originalObj.jsonCloneObject;

He creado para mi una extensión que convierte ICollection de elementos que no implementan IClonable

static class CollectionExtensions
{
    public static ICollection<T> Clone<T>(this ICollection<T> listToClone)
    {
        var array = new T[listToClone.Count];
        listToClone.CopyTo(array,0);
        return array.ToList();
    }
}

Otra cosa: podrías usar la reflexión. Si guardará este caché correctamente, clonará 1,000,000 de objetos en 5.6 segundos (lamentablemente, 16.4 segundos con objetos internos).

[ProtoContract(ImplicitFields = ImplicitFields.AllPublic)]
public class Person
{
       ...
      Job JobDescription
       ...
}

[ProtoContract(ImplicitFields = ImplicitFields.AllPublic)]
public class Job
{...
}

private static readonly Type stringType = typeof (string);

public static class CopyFactory
{
    static readonly Dictionary<Type, PropertyInfo[]> ProperyList = new Dictionary<Type, PropertyInfo[]>();

    private static readonly MethodInfo CreateCopyReflectionMethod;

    static CopyFactory()
    {
        CreateCopyReflectionMethod = typeof(CopyFactory).GetMethod("CreateCopyReflection", BindingFlags.Static | BindingFlags.Public);
    }

    public static T CreateCopyReflection<T>(T source) where T : new()
    {
        var copyInstance = new T();
        var sourceType = typeof(T);

        PropertyInfo[] propList;
        if (ProperyList.ContainsKey(sourceType))
            propList = ProperyList[sourceType];
        else
        {
            propList = sourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
            ProperyList.Add(sourceType, propList);
        }

        foreach (var prop in propList)
        {
            var value = prop.GetValue(source, null);
            prop.SetValue(copyInstance,
                value != null && prop.PropertyType.IsClass && prop.PropertyType != stringType ? CreateCopyReflectionMethod.MakeGenericMethod(prop.PropertyType).Invoke(null, new object[] { value }) : value, null);
        }

        return copyInstance;
    }

Lo medí de una manera simple, usando la clase Watcher.

 var person = new Person
 {
     ...
 };

 for (var i = 0; i < 1000000; i++)
 {
    personList.Add(person);
 }
 var watcher = new Stopwatch();
 watcher.Start();
 var copylist = personList.Select(CopyFactory.CreateCopyReflection).ToList();
 watcher.Stop();
 var elapsed = watcher.Elapsed;

RESULTADO: Con el objeto interno PersonInstance - 16.4, PersonInstance = null - 5.6

CopyFactory es solo mi clase de prueba donde tengo una docena de pruebas que incluyen el uso de expresiones. Podría implementar esto en otra forma en una extensión o lo que sea. No te olvides del almacenamiento en caché.

No probé la serialización todavía, pero dudo en una mejora con un millón de clases. Voy a intentar algo rápido protobuf / newton.

PD: en aras de la simplicidad de lectura, solo usé auto-propiedad aquí. Podría actualizar con FieldInfo, o debería implementarlo fácilmente por su cuenta.

Recientemente probé el serializador Protocol Buffers con la función DeepClone fuera de la caja. Gana con 4.2 segundos en un millón de objetos simples, pero cuando se trata de objetos internos, gana con el resultado de 7.4 segundos.

Serializer.DeepClone(personList);

RESUMEN: Si no tiene acceso a las clases, esto ayudará. De lo contrario, depende de la cuenta de los objetos. Creo que podrías usar la reflexión de hasta 10,000 objetos (quizás un poco menos), pero por más que esto, el serializador de Protocol Buffers tendrá un mejor desempeño.


Para clonar una lista solo llame a .ToList ()

Microsoft (R) Roslyn C# Compiler version 2.3.2.62116
Loading context from 'CSharpInteractive.rsp'.
Type "#help" for more information.
> var x = new List<int>() { 3, 4 };
> var y = x.ToList();
> x.Add(5)
> x
List<int>(3) { 3, 4, 5 }
> y
List<int>(2) { 3, 4 }
> 

Puede utilizar el método de extensión:

namespace extension
{
    public class ext
    {
        public static List<double> clone(this List<double> t)
        {
            List<double> kop = new List<double>();
            int x;
            for (x = 0; x < t.Count; x++)
            {
                kop.Add(t[x]);
            }
            return kop;
        }
   };

}

Puede clonar todos los objetos utilizando sus miembros de tipo de valor, por ejemplo, considere esta clase:

public class matrix
{
    public List<List<double>> mat;
    public int rows,cols;
    public matrix clone()
    { 
        // create new object
        matrix copy = new matrix();
        // firstly I can directly copy rows and cols because they are value types
        copy.rows = this.rows;  
        copy.cols = this.cols;
        // but now I can no t directly copy mat because it is not value type so
        int x;
        // I assume I have clone method for List<double>
        for(x=0;x<this.mat.count;x++)
        {
            copy.mat.Add(this.mat[x].clone());
        }
        // then mat is cloned
        return copy; // and copy of original is returned 
    }
};

Nota: si realiza algún cambio en la copia (o clonación) no afectará al objeto original.


Puede utilizar un método de extensión.

static class Extensions
{
    public static IList<T> Clone<T>(this IList<T> listToClone) where T: ICloneable
    {
        return listToClone.Select(item => (T)item.Clone()).ToList();
    }
}

Si solo te importan los tipos de valor ...

Y ya sabes el tipo:

List<int> newList = new List<int>(oldList);

Si no conoce el tipo anterior, necesitará una función auxiliar:

List<T> Clone<T>(IEnumerable<T> oldList)
{
    return newList = new List<T>(oldList);
}

El justo:

List<string> myNewList = Clone(myOldList);

Si sus elementos son tipos de valor, entonces simplemente puede hacer:

List<YourType> newList = new List<YourType>(oldList);

Sin embargo, si son tipos de referencia y desea una copia profunda (suponiendo que sus elementos implementan ICloneable correctamente), podría hacer algo como esto:

List<ICloneable> oldList = new List<ICloneable>();
List<ICloneable> newList = new List<ICloneable>(oldList.Count);

oldList.ForEach((item) =>
    {
        newList.Add((ICloneable)item.Clone());
    });

Obviamente, reemplace ICloneable en los genéricos anteriores y emita cualquier tipo de elemento que implemente ICloneable .

Si su tipo de elemento no admite ICloneable pero tiene un constructor de copia, podría hacer esto en su lugar:

List<YourType> oldList = new List<YourType>();
List<YourType> newList = new List<YourType>(oldList.Count);

oldList.ForEach((item)=>
    {
        newList.Add(new YourType(item));
    });

Personalmente, evitaría ICloneable debido a la necesidad de garantizar una copia profunda de todos los miembros. En su lugar, sugeriría el constructor de copia o un método de fábrica como YourType.CopyFrom(YourType itemToCopy) que devuelve una nueva instancia de YourType .

Cualquiera de estas opciones podría ser envuelta por un método (extensión o de otro tipo).


También puede simplemente convertir la lista a una matriz usando ToArray , y luego clonar la matriz usando Array.Clone(...) . Dependiendo de sus necesidades, los métodos incluidos en la clase Array podrían satisfacer sus necesidades.


Usar el AutoMapper (o la biblioteca de mapeo que prefieras) para clonar es simple y mucho más fácil de mantener.

Defina su mapeo:

Mapper.CreateMap<YourType, YourType>();

Hacer la magia

YourTypeList.ConvertAll(Mapper.Map<YourType, YourType>);

    public List<TEntity> Clone<TEntity>(List<TEntity> o1List) where TEntity : class , new()
    {
        List<TEntity> retList = new List<TEntity>();
        try
        {
            Type sourceType = typeof(TEntity);
            foreach(var o1 in o1List)
            {
                TEntity o2 = new TEntity();
                foreach (PropertyInfo propInfo in (sourceType.GetProperties()))
                {
                    var val = propInfo.GetValue(o1, null);
                    propInfo.SetValue(o2, val);
                }
                retList.Add(o2);
            }
            return retList;
        }
        catch
        {
            return retList;
        }
    }

 //try this
 List<string> ListCopy= new List<string>(OldList);
 //or try
 List<T> ListCopy=OldList.ToList();

public static Object CloneType(Object objtype)
{
    Object lstfinal = new Object();

    using (MemoryStream memStream = new MemoryStream())
    {
        BinaryFormatter binaryFormatter = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.Clone));
        binaryFormatter.Serialize(memStream, objtype); memStream.Seek(0, SeekOrigin.Begin);
        lstfinal = binaryFormatter.Deserialize(memStream);
    }

    return lstfinal;
}

public static object DeepClone(object obj) 
{
  object objResult = null;
  using (MemoryStream  ms = new MemoryStream())
  {
    BinaryFormatter  bf =   new BinaryFormatter();
    bf.Serialize(ms, obj);

    ms.Position = 0;
    objResult = bf.Deserialize(ms);
  }
  return objResult;
}

Esta es una forma de hacerlo con C # y .NET 2.0. Tu objeto requiere ser [Serializable()] . El objetivo es perder todas las referencias y construir otras nuevas.





clone