我在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
,因为需要保证所有成员的深度拷贝。取而代之的是,我建议使用复制构造函数或工厂方法,如YourType.CopyFrom(YourType itemToCopy)
,该方法返回一个YourType
的新实例。
这些选项中的任何一个都可以由一个方法(扩展或其他)来包装。
对于一个浅层拷贝,你可以使用通用List类的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 (MemoryStream ms = new MemoryStream())
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(ms, obj);
ms.Position = 0;
objResult = bf.Deserialize(ms);
}
return objResult;
}
这是用C#和.NET 2.0做的一种方法。
你的对象需要是[Serializable()]
。
我们的目标是失去所有的引用并建立新的引用。
稍微修改后也可以克隆。
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;
}
要克隆一个列表,只要调用.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 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 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;
}
如果有人读到这篇文章,那我就很幸运了......。 但是为了在我的Clone方法中不返回一个类型对象的列表,我创建了一个接口。
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();
}
有人喜欢吗? 有什么改进吗?
您可以使用扩展方法。
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
}
};
请注意,如果你在复制(或克隆)时做了任何改变,不会影响到原始对象。 如果你在复制(或克隆)时做了任何改变,将不会影响原始对象。
如果你需要一个同样容量的克隆列表,你可以试试这个。
public static List<T> Clone<T>(this List<T> oldList)
{
var newList = new List<T>(oldList.Capacity);
newList.AddRange(oldList);
return newList;
}
我的朋友Gregor Martinovic和我想出了这个使用JavaScript Serializer的简单解决方案。 无需将类标记为Serializable,在我们的测试中,使用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][1]的更快选项。
public static T DeepCopy<T>(this T value)
{
string json = JsonConvert.SerializeObject(value);
return JsonConvert.DeserializeObject<T>(json);
}