C#에서 범용 목록을 복제하려면 어떻게 해야 하나요?
C#에 오브젝트의 범용 리스트가 있어 그 리스트를 복제하고 싶다.은 복제할 수 , 복제는 할 수 있는 것 같습니다.list.Clone().
쉬운 방법이 없을까요?
요소가 값 유형인 경우 다음을 수행할 수 있습니다.
List<YourType> newList = new List<YourType>(oldList);
카피를 로 하는 실장되어 있는 )ICloneable는 할 수
List<ICloneable> oldList = new List<ICloneable>();
List<ICloneable> newList = new List<ICloneable>(oldList.Count);
oldList.ForEach((item) =>
{
newList.Add((ICloneable)item.Clone());
});
""를 합니다.ICloneable, 는 「유형」을 .ICloneable.
이 지원되지 않는 ICloneable복사기가 있습니다.대신 다음과 같이 할 수 있습니다.
List<YourType> oldList = new List<YourType>();
List<YourType> newList = new List<YourType>(oldList.Count);
oldList.ForEach((item)=>
{
newList.Add(new YourType(item));
});
.ICloneable모든 멤버들의 깊은 복사를 보장해야 하기 때문입니다.대신 나 대, 사, method, , method, method, method, method, method, method, method, method, method, method, method, method, method, method, method, method, method, method, method method, , methodYourType.CopyFrom(YourType itemToCopy)됩니다.YourType.
이러한 옵션은 메서드(확장 또는 기타)로 래핑할 수 있습니다.
확장 방법을 사용할 수 있습니다.
static class Extensions
{
public static IList<T> Clone<T>(this IList<T> listToClone) where T: ICloneable
{
return listToClone.Select(item => (T)item.Clone()).ToList();
}
}
얕은 복사본의 경우 대신 일반 목록 클래스의 GetRange 메서드를 사용할 수 있습니다.
List<int> oldList = new List<int>( );
// Populate oldList...
List<int> newList = oldList.GetRange(0, oldList.Count);
인용처:범용 레시피
public static object DeepClone(object obj)
{
object objResult = null;
using (var ms = new MemoryStream())
{
var bf = new BinaryFormatter();
bf.Serialize(ms, obj);
ms.Position = 0;
objResult = bf.Deserialize(ms);
}
return objResult;
}
이것은 C# 및 를 사용하는 경우의1가지 방법입니다.NET 2.0 는 신신음음음음음음음음음음음음음음음음음 net로 해야 합니다.[Serializable()]목표는 모든 레퍼런스를 잃고 새로운 레퍼런스를 구축하는 것입니다.
목록을 복제하려면 을 클릭하십시오.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 }
>
약간의 변경 후 다음 복제도 가능합니다.
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;
}
는 제외합니다.List<T>목록을 복제하는 가장 좋은 방법은 오래된 목록을 수집 파라미터로 사용하여 새 목록을 작성하는 것입니다.
List<T> myList = ...;
List<T> cloneOfMyList = new List<T>(myList);
「 」로의 myList를 들어 또는 을 주지 .cloneOfMyList그리고 역도 성립.
그러나 두 목록에 포함된 실제 개체는 여전히 동일합니다.
AutoMapper(또는 원하는 매핑 lib)를 사용하여 복제는 단순하고 유지보수가 가능합니다.
매핑을 정의합니다.
Mapper.CreateMap<YourType, YourType>();
마법을 부려라:
YourTypeList.ConvertAll(Mapper.Map<YourType, YourType>);
값 유형만 신경 쓴다면...
그리고 그 종류도 알겠죠?
List<int> newList = new List<int>(oldList);
이전에 유형을 모르는 경우 도우미 기능이 필요합니다.
List<T> Clone<T>(IEnumerable<T> oldList)
{
return newList = new List<T>(oldList);
}
그 이유는 다음과 같습니다.
List<string> myNewList = Clone(myOldList);
당신이 이미 뉴턴소프트를 참조했다면.프로젝트의 Json 및 객체는 언제든지 사용할 수 있습니다.
List<T> newList = JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(listToCopy))
가장 효율적인 방법은 아닐 수도 있지만, 100/1000회 이상 하지 않으면 속도 차이를 알아차리지 못할 수도 있습니다.
상세한 카피에서는, ICloneable이 올바른 솔루션이지만, 여기에서는 ICloneable 인터페이스 대신 컨스트럭터를 사용하는 ICloneable에 대한 유사한 접근방식이 있습니다.
public class Student
{
public Student(Student student)
{
FirstName = student.FirstName;
LastName = student.LastName;
}
public string FirstName { get; set; }
public string LastName { get; set; }
}
// wherever you have the list
List<Student> students;
// and then where you want to make a copy
List<Student> copy = students.Select(s => new Student(s)).ToList();
복사를 하려면 다음과 같은 라이브러리가 필요합니다.
using System.Linq
시스템 대신 for 루프를 사용할 수도 있습니다.린크, 하지만 린크는 간결하고 깔끔하게 표현해.마찬가지로 다른 답변에 따라 확장 방법 등을 만들 수 있지만, 이 중 어느 것도 필요하지 않습니다.
이 테스트에서는 클래스에 시리얼 가능 플래그를 붙일 필요가 없으며, Newtonsoft JsonSerializer를 사용하여 BinaryFormatter를 사용하는 것보다 더 빨리 클래스를 플래그 지정할 필요가 없습니다.모든 개체에 사용할 수 있는 확장 메서드를 사용합니다.
주의: 프라이빗멤버는 복제되지 않음
표준.NET JavascriptSerializer 옵션:
public static T DeepCopy<T>(this T value)
{
JavaScriptSerializer js = new JavaScriptSerializer();
string json = js.Serialize(value);
return js.Deserialize<T>(json);
}
Newtonsoft JSON을 사용한 빠른 옵션:
public static T DeepCopy<T>(this T value)
{
string json = JsonConvert.SerializeObject(value);
return JsonConvert.DeserializeObject<T>(json);
}
//try this
List<string> ListCopy= new List<string>(OldList);
//or try
List<T> ListCopy=OldList.ToList();
누가 이걸 읽으면 난 운이 좋을 거야단, Clone 메서드에서 type 객체의 목록을 반환하지 않기 위해 인터페이스를 만들었습니다.
public interface IMyCloneable<T>
{
T Clone();
}
다음으로 내선번호를 지정했습니다.
public static List<T> Clone<T>(this List<T> listToClone) where T : IMyCloneable<T>
{
return listToClone.Select(item => (T)item.Clone()).ToList();
}
여기에서는 A/V 마킹소프트웨어에 인터페이스를 실장하고 있습니다.Clone() 메서드에서 VidMark 목록을 반환하도록 하고 싶습니다(ICloneable 인터페이스는 메서드에서 오브젝트 목록을 반환하도록 했습니다).
public class VidMark : IMyCloneable<VidMark>
{
public long Beg { get; set; }
public long End { get; set; }
public string Desc { get; set; }
public int Rank { get; set; } = 0;
public VidMark Clone()
{
return (VidMark)this.MemberwiseClone();
}
}
마지막으로 클래스 내에서의 내선번호 사용방법:
private List<VidMark> _VidMarks;
private List<VidMark> _UndoVidMarks;
//Other methods instantiate and fill the lists
private void SetUndoVidMarks()
{
_UndoVidMarks = _VidMarks.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 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 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;
}
}
같은 용량의 클론 리스트가 필요한 경우는, 다음과 같이 시험할 수 있습니다.
public static List<T> Clone<T>(this List<T> oldList)
{
var newList = new List<T>(oldList.Capacity);
newList.AddRange(oldList);
return newList;
}
컬렉션의 상세한 복사가 필요한 경우, 다음과 같은 방법을 선호합니다.
public static IEnumerable<T> DeepCopy<T>(this IEnumerable<T> collectionToDeepCopy)
{
var serializedCollection = JsonConvert.SerializeObject(collectionToDeepCopy);
return JsonConvert.DeserializeObject<IEnumerable<T>>(serializedCollection);
}
확장 방식을 사용할 수 있습니다.
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;
}
};
}
값 유형 멤버를 사용하여 모든 개체를 복제할 수 있습니다. 예를 들어 다음 클래스를 고려하십시오.
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
}
};
주의: 복사(또는 복제)를 변경해도 원래 개체에는 영향을 주지 않습니다.
이 경우 캐스트를 사용하면 다음과 같이 얕은 복사에 도움이 될 수 있습니다.
IList CloneList(IList list)
{
IList result;
result = (IList)Activator.CreateInstance(list.GetType());
foreach (object item in list) result.Add(item);
return result;
}
일반 목록에 적용됨:
List<T> Clone<T>(List<T> argument) => (List<T>)CloneList(argument);
오브젝트를 복사하기 위해 오토마퍼를 사용합니다.하나의 객체를 매핑하는 매핑을 설정했을 뿐입니다.이 작업은 원하는 방식으로 래핑할 수 있습니다.
http://automapper.codeplex.com/
IClonable을 구현하지 않은 아이템의 ICollection을 변환하는 확장 기능을 만들었습니다.
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();
}
}
.ToArray를 사용하여 Array.Clone(...)필요에 따라 어레이 클래스에 포함된 메서드가 고객의 요구를 충족시킬 수 있습니다.
다음 코드는 최소한의 변경으로 목록으로 전송됩니다.
기본적으로는 연속되는 루프마다 더 큰 범위에서 새로운 난수를 삽입함으로써 동작합니다.동일하거나 그보다 높은 숫자가 이미 존재하는 경우 해당 난수들을 1 위로 이동시켜 더 큰 범위의 랜덤 인덱스로 전송합니다.
// 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;
}
또 다른 것은 반성을 할 수 있다는 것입니다.이 캐시를 올바르게 하면 1,000,000개의 개체가 5.6초 내에 복제됩니다(내부 개체의 경우 16.4초).
[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;
}
워처 클래스를 사용하여 간단하게 측정했습니다.
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;
결과: 내부 객체 PersonInstance - 16.4의 경우 PersonInstance = null - 5.6
Copy Factory는 표현식 사용을 포함한 12개의 테스트를 수행하는 테스트 클래스입니다.이것을 다른 형태로 확장 또는 다른 형태로 구현할 수 있습니다.캐싱도 잊지 마세요.
아직 연재 테스트를 해보진 않았지만, 100만 개의 클래스가 있는 개선은 의심스럽네요.빠른 프로토부프/뉴턴으로 하겠습니다.
추신: 간결하게 읽기 위해서, 저는 자동차 소유물만을 사용했습니다.FieldInfo로 업데이트 할 수도 있고 직접 쉽게 구현할 수도 있습니다.
최근에 DeepClone 기능을 바로 사용할 수 있는 Protocol Buffers 시리얼라이저를 테스트했습니다.단순 객체 100만 개에서는 4.2초로 이기지만 내부 객체에서는 7.4초로 이긴다.
Serializer.DeepClone(personList);
요약: 클래스에 액세스할 수 없는 경우 도움이 됩니다.그렇지 않으면 개체 수에 따라 달라집니다.리플렉션을 사용할 수 있는 객체는 최대 10,000개(약간 적을 수 있음)이지만, 이 이상의 경우 Protocol Buffers serializer가 더 잘 작동합니다.
JSON serializer 및 deserializer를 사용하여 C# 내의 개체를 복제하는 간단한 방법이 있습니다.
확장 클래스를 만들 수 있습니다.
using Newtonsoft.Json;
static class typeExtensions
{
[Extension()]
public static T jsonCloneObject<T>(T source)
{
string json = JsonConvert.SerializeObject(source);
return JsonConvert.DeserializeObject<T>(json);
}
}
복제 및 개체화 방법:
obj clonedObj = originalObj.jsonCloneObject;
딥 클론의 경우 다음과 같이 반사를 사용합니다.
public List<T> CloneList<T>(IEnumerable<T> listToClone) {
Type listType = listToClone.GetType();
Type elementType = listType.GetGenericArguments()[0];
List<T> listCopy = new List<T>();
foreach (T item in listToClone) {
object itemCopy = Activator.CreateInstance(elementType);
foreach (PropertyInfo property in elementType.GetProperties()) {
elementType.GetProperty(property.Name).SetValue(itemCopy, property.GetValue(item));
}
listCopy.Add((T)itemCopy);
}
return listCopy;
}
List 또는 IEnumberable을 자유롭게 사용할 수 있습니다.
를 사용할 수 있습니다.List<T>.ConvertAll(Converter<T, T>)method는 원래 목록의 모든 요소를 포함하는 새 목록을 만들고 입력 값을 반환하는 변환 함수를 사용합니다.
List<int> originalList = new List<int> { 1, 2, 3, 4, 5 };
List<int> clonedList = new List<int>(originalList.ConvertAll(x => x));
언급URL : https://stackoverflow.com/questions/222598/how-do-i-clone-a-generic-list-in-c
'programing' 카테고리의 다른 글
| xcode4의 프레임워크와 정적 라이브러리의 차이 및 호출 방법 (0) | 2023.04.14 |
|---|---|
| 날짜 시간 문자열을 Bash에서 에폭으로 변환 (0) | 2023.04.14 |
| makefile의 여러 줄 bash 명령어 (0) | 2023.04.14 |
| Linux는 DOS 일시 중지에 상당합니까? (0) | 2023.04.14 |
| 데이터 바인딩을 통해 WPF 하이퍼링크의 텍스트를 설정하려면 어떻게 해야 합니까? (0) | 2023.04.14 |