实际上有三种可能的方法来做到这一点:
public static ICollection<T> CreateCopyReflection<T> (this ICollection<T> c)
{
var n = (ICollection<T>) Activator.CreateInstance (c.GetType());
foreach (var item in c)
n.Add (item);
return n;
}
public static IEnumerable<T> CreateCopyLinq<T> (this IEnumerable<T> c) => c.Select (arg => arg);
public static IEnumerable<T> CreateCopyEnumeration<T> (this IEnumerable<T> c)
{
foreach (var item in c)
yield return item;
}
请注意,我们可以在这里使用 IEnumerables 而无需担心,因为 ICollection<T> 派生自 IEnumerable<T>。
第一个解决方案使用反射创建副本,第二个使用 Linq,第三个使用枚举。我们现在可以使用以下代码对此进行分析:
var myList = Enumerable.Range (0, 100000000).ToList();
var trueCopy = new List<int> (myList);
var time = Environment.TickCount;
var copyOne = myList.CreateCopyReflection();
Console.WriteLine($"Refelection copy: {Environment.TickCount - time}");
time = Environment.TickCount;
var copyTwo = myList.CreateCopyLinq ();
Console.WriteLine ($"Linq copy: {Environment.TickCount - time}");
time = Environment.TickCount;
var copyThree = myList.CreateCopyEnumeration ();
Console.WriteLine ($"Enumeration copy: {Environment.TickCount - time}");
time = Environment.TickCount;
结果:
Reflection copy: 1375
Linq copy: 0
Enumeration copy: 0
但是,我们必须记住,c# 在这里是惰性的,这意味着它实际上并没有计算值,所以我们只能在枚举 IEnumerables 时得到可比较的结果:
var myList = Enumerable.Range (0, 100000000).ToList();
var trueCopy = new List<int> (myList);
var time = Environment.TickCount;
var copyOne = myList.CreateCopyReflection().ToList();
Console.WriteLine($"Reflection copy: {Environment.TickCount - time}");
time = Environment.TickCount;
var copyTwo = myList.CreateCopyLinq ().ToList();
Console.WriteLine ($"Linq copy: {Environment.TickCount - time}");
time = Environment.TickCount;
var copyThree = myList.CreateCopyEnumeration ().ToList();
Console.WriteLine ($"Enumeration copy: {Environment.TickCount - time}");
time = Environment.TickCount;
结果:
Reflection copy: 1500
Linq copy: 1625
Enumeration copy: 3140
所以我们可以看到枚举是最慢的,其次是linq,然后是反射。但是,反射和 linq 非常接近,并且 linq 具有巨大的(至少在很多情况下)优势,即它是惰性的(以及枚举),这就是我使用它的原因。
比较一下 if cascades 很有趣:
private static void Main ()
{
var myList = Enumerable.Range (0, 100000000).ToList();
var trueCopy = new List<int> (myList);
var time = Environment.TickCount;
var copyOne = myList.CreateCopyReflection().ToList();
Console.WriteLine($"Reflection copy: {Environment.TickCount - time}");
time = Environment.TickCount;
var copyTwo = myList.CreateCopyLinq ().ToList();
Console.WriteLine ($"Linq copy: {Environment.TickCount - time}");
time = Environment.TickCount;
var copyThree = myList.CreateCopyEnumeration ().ToList();
Console.WriteLine ($"Enumeration copy: {Environment.TickCount - time}");
time = Environment.TickCount;
var copyFour = myList.CreateCopyCascade ();
Console.WriteLine($"Cascade copy: {Environment.TickCount - time}");
time = Environment.TickCount;
Console.ReadLine ();
}
public static ICollection<T> CreateCopyReflection<T> (this ICollection<T> c)
{
var n = (ICollection<T>) Activator.CreateInstance (c.GetType());
foreach (var item in c)
n.Add (item);
return n;
}
public static IEnumerable<T> CreateCopyLinq<T> (this IEnumerable<T> c) => c.Select (arg => arg);
public static IEnumerable<T> CreateCopyEnumeration<T> (this IEnumerable<T> c)
{
foreach (var item in c)
yield return item;
}
public static ICollection<T> CreateCopyCascade<T> (this ICollection<T> c)
{
if (c.GetType() == typeof(List<T>))
return new List<T> (c);
if (c.GetType() == typeof(HashSet<T>))
return new HashSet<T> (c);
//...
return null;
}
结果:
Reflection copy: 1594
Linq copy: 1750
Enumeration copy: 3141
Cascade copy: 172
因此我们可以看到级联速度更快 - 但是,如果创建其他从 ICollection 派生的集合,它将无法工作,因为它不会知道它们,所以这个解决方案不是非常可取的。