without una otra lista datos copiar clonar c# generics list clone

otra - clonar una lista c#



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

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.

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; }


El siguiente código debe transferirse a una lista con cambios mínimos.

Básicamente funciona insertando un nuevo número aleatorio de un rango mayor con cada ciclo sucesivo. Si ya existen números que son iguales o más altos, cambie esos números aleatorios hacia arriba para que se transfieran al nuevo rango más grande de índices aleatorios.

// Example Usage int[] indexes = getRandomUniqueIndexArray(selectFrom.Length, toSet.Length); for(int i = 0; i < toSet.Length; i++) toSet[i] = selectFrom[indexes[i]]; private int[] getRandomUniqueIndexArray(int length, int count) { if(count > length || count < 1 || length < 1) return new int[0]; int[] toReturn = new int[count]; if(count == length) { for(int i = 0; i < toReturn.Length; i++) toReturn[i] = i; return toReturn; } Random r = new Random(); int startPos = count - 1; for(int i = startPos; i >= 0; i--) { int index = r.Next(length - i); for(int j = startPos; j > i; j--) if(toReturn[j] >= index) toReturn[j]++; toReturn[i] = index; } return toReturn; }


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(); } }


Mi amigo Gregor Martinovic y yo creamos esta solución fácil utilizando un serializador de JavaScript. No es necesario marcar las clases como serializables y en nuestras pruebas con Newtonsoft JsonSerializer incluso más rápido que con BinaryFormatter. Con métodos de extensión utilizables en cada objeto.

Opción estándar .NET JavascriptSerializer:

public static T DeepCopy<T>(this T value) { JavaScriptSerializer js = new JavaScriptSerializer(); string json = js.Serialize(value); return js.Deserialize<T>(json); }

Opción más rápida utilizando Newtonsoft JSON :

public static T DeepCopy<T>(this T value) { string json = JsonConvert.SerializeObject(value); return JsonConvert.DeserializeObject<T>(json); }


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 } >


Para una copia superficial, puede utilizar el método GetRange de la clase de lista genérica.

List<int> oldList = new List<int>( ); // Populate oldList... List<int> newList = oldList.GetRange(0, oldList.Count);

Citado de: Recetas de genéricos


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 necesita una lista clonada con la misma capacidad, puede intentar esto:

public static List<T> Clone<T>(this List<T> oldList) { var newList = new List<T>(oldList.Capacity); newList.AddRange(oldList); return newList; }


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).


Si ya ha hecho referencia a Newtonsoft.Json en su proyecto y sus objetos se pueden serializar, siempre puede usar:

List<T> newList = JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(listToCopy))

Posiblemente no sea la forma más eficiente de hacerlo, pero a menos que lo esté haciendo cientos de miles de veces, es posible que ni siquiera note la diferencia de velocidad.


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>);


Yo uso automapper para copiar un objeto. Acabo de configurar una asignación que asigna un objeto a sí mismo. Puedes envolver esta operación como quieras.

http://automapper.codeplex.com/


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 class CloneableList<T> : List<T>, ICloneable where T : ICloneable { public object Clone() { var clone = new List<T>(); ForEach(item => clone.Add((T)item.Clone())); return clone; } }


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.