Если Ваши элементы являются типами значения, то можно просто сделать:
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
.
Любая из этих опций могла быть обернута методом (расширение или иначе).
Я сильно подозреваю, что упаковка вызовов будет намного эффективнее, чем использование DynamicInvoke
. Тогда ваш код будет:
internal sealed class TypeDispatchProcessor
{
private readonly Dictionary<Type, Action<object>> _actionByType
= new Dictionary<Type, Action<object>>();
public void RegisterProcedure<T>(Action<T> action)
{
_actionByType[typeof(T)] = item => action((T) item);
}
public void ProcessItem(object item)
{
Action<object> action;
if (_actionByType.TryGetValue(item.GetType(), out action))
{
action(item);
}
}
}
Его стоит протестировать, но я думаю, вы найдете это намного более эффективным. DynamicInvoke
должен проверять все аргументы с помощью отражения и т. Д. Вместо простого преобразования в обернутом делегате.
Итак, я провел некоторые измерения.
var delegates = new List<Delegate>();
var actions = new List<Action<object>>();
const int dataCount = 100;
const int loopCount = 10000;
for (int i = 0; i < dataCount; i++)
{
Action<int> a = d => { };
delegates.Add(a);
actions.Add(o => a((int)o));
}
var sw = Stopwatch.StartNew();
for (int i = 0; i < loopCount; i++)
{
foreach (var action in actions)
action(i);
}
Console.Out.WriteLine("{0:#,##0} Action<object> calls in {1:#,##0.###} ms",
loopCount * dataCount, sw.Elapsed.TotalMilliseconds);
sw = Stopwatch.StartNew();
for (int i = 0; i < loopCount; i++)
{
foreach (var del in delegates)
del.DynamicInvoke(i);
}
Console.Out.WriteLine("{0:#,##0} DynamicInvoke calls in {1:#,##0.###} ms",
loopCount * dataCount, sw.Elapsed.TotalMilliseconds);
Я создал ряд элементов для косвенного вызова, чтобы избежать какой-либо оптимизации, которую может выполнить JIT.
Результаты весьма убедительны!
1,000,000 Action calls in 47.172 ms 1,000,000 Delegate.DynamicInvoke calls in 12,035.943 ms 1,000,000 Action calls in 44.686 ms 1,000,000 Delegate.DynamicInvoke calls in 12,318.846 ms
Итак, в этом случае заменяем вызов на DynamicInvoke
для дополнительного косвенного вызова и приведения были примерно 270 раз быстрее . Все в день работы.