Я провел некоторое сравнение между ними (я бы записал минимальные детали):
public static T Instance() //~1800 ms
{
return new T();
}
public static T Instance() //~1800 ms
{
return new Activator.CreateInstance<T>();
}
public static readonly Func<T> Instance = () => new T(); //~1800 ms
public static readonly Func<T> Instance = () =>
Activator.CreateInstance<T>(); //~1800 ms
//works for types with no default constructor as well
public static readonly Func<T> Instance = () =>
(T)FormatterServices.GetUninitializedObject(typeof(T)); //~2000 ms
public static readonly Func<T> Instance =
Expression.Lambda<Func<T>>(Expression.New(typeof(T))).Compile();
//~50 ms for classes and ~100 ms for structs
Как говорит CD, скомпилированное выражение является самым быстрым и с большим отрывом. Все методы, кроме (T)FormatterServices.GetUninitializedObject(typeof(T))
, работают только для типов с конструктором по умолчанию.
И кэширование скомпилированного результирующего делегата тривиально, когда у вас есть статический класс для универсального типа. Как:
public static class New<T> where T : new()
{
public static readonly Func<T> Instance = Expression.Lambda<Func<T>>
(
Expression.New(typeof(T))
).Compile();
}
Обратите внимание на ограничение new
. Звоните что угодно
MyType me = New<MyType>.Instance();
За исключением тех случаев, когда класс загружается в первый раз, выполнение будет самым быстрым.
Чтобы иметь класс, который обрабатывает оба типа с конструктором по умолчанию и без него, я выбрал гибридный подход, отсюда :
public static class New<T>
{
public static readonly Func<T> Instance = Creator();
static Func<T> Creator()
{
Type t = typeof(T);
if (t == typeof(string))
return Expression.Lambda<Func<T>>(Expression.Constant(string.Empty)).Compile();
if (t.HasDefaultConstructor())
return Expression.Lambda<Func<T>>(Expression.New(t)).Compile();
return () => (T)FormatterServices.GetUninitializedObject(t);
}
}
public static bool HasDefaultConstructor(this Type t)
{
return t.IsValueType || t.GetConstructor(Type.EmptyTypes) != null;
}
Также будет эффективно обрабатывать типы значений.
Обратите внимание, что (T)FormatterServices.GetUninitializedObject(t)
не удастся для string
. Следовательно, имеется специальная обработка для возврата пустой строки.