나는 우리 응용 프로그램의 성능을 향상 시키려고 노력하고 있습니다. Activator.CreateInstance 호출이 많아서 슬픔이 생깁니다.
인터페이스 (ITabDocument)를 기반으로 많은 클래스를 인스턴스화하고이 코드를 사용하여 주위를 둘러 보았습니다.
이 코드는 우리가 가진 Activator.CreateInstance 코드를 사용하는 것보다 낫지는 않습니다.
public static Func<T> CreateInstance<T>(Type objType) where T : class, new()
{
var dynMethod = new DynamicMethod("DM$OBJ_FACTORY_" + objType.Name, objType, null, objType);
ILGenerator ilGen = dynMethod.GetILGenerator();
ilGen.Emit(OpCodes.Newobj, objType.GetConstructor(Type.EmptyTypes));
ilGen.Emit(OpCodes.Ret);
return (Func<T>)dynMethod.CreateDelegate(typeof(Func<T>));
}
왜 내가이 모든 일을하는지 궁금해.
ITabDocument document = CreateInstance<ITabDocument>(Type.GetType("[Company].Something"));
위와 관련하여 도움이되는 객체를 만드는 더 좋은 방법이 있습니까? 콘크리트 타입이 확실하지 않을 때 조금 힘듭니다.
나는 이들 사이에서 벤치마킹을했다 (나는 최소한의 세부 사항을 적어 둔다).
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
. 따라서 빈 문자열을 반환하기 위해 string에 대한 특수 처리가 제 위치에 있습니다.
typeof(T)
). - nawfal
도움이 될 수 있습니다.Activator.CreateInstance 또는 ConstructorInfo.Invoke를 사용하지 말고 컴파일 된 람다 식을 사용하십시오.:
// Make a NewExpression that calls the ctor with the args we just created NewExpression newExp = Expression.New(ctor, argsExp); // Create a lambda with the New expression as body and our param object[] as arg LambdaExpression lambda = Expression.Lambda(typeof(ObjectActivator), newExp, param); // Compile it ObjectActivator compiled = (ObjectActivator)lambda.Compile();
문제는 어딘가에 결과를 저장하고 그 결과를 반복해서 사용하는 대신에 CreateInstance를 계속해서 반복적으로 호출 할 것이므로 아마도 그 안에 캐싱 할 것입니다.
internal static class DelegateStore<T> {
internal static IDictionary<string, Func<T>> Store = new ConcurrentDictionary<string,Func<T>>();
}
public static T CreateInstance<T>(Type objType) where T : class
{
Func<T> returnFunc;
if(!DelegateStore<T>.Store.TryGetValue(objType.FullName, out returnFunc)) {
var dynMethod = new DynamicMethod("DM$OBJ_FACTORY_" + objType.Name, objType, null, objType);
ILGenerator ilGen = dynMethod.GetILGenerator();
ilGen.Emit(OpCodes.Newobj, objType.GetConstructor(Type.EmptyTypes));
ilGen.Emit(OpCodes.Ret);
returnFunc = (Func<T>)dynMethod.CreateDelegate(typeof(Func<T>));
DelegateStore<T>.Store[objType.FullName] = returnFunc;
}
return returnFunc();
}
DelegateStore<T>
왜냐하면 그 범용 클래스는 자동적으로 유일한 per-T
이미 인스턴스화. 그것이 사실 일지라도 이것은 사실입니다.static
수업. 그래서 당신이 필요로하는 모든 것DelegateStore<T>
간단하게internal static Func<T> _cached_func;
가지고 계시다시피, 많은 사전을 만드십시오 - 모든 것을위한 새로운 것T
- 캐시 된 하나의 대리자 만 포함하는 각. - Glenn Slayden
같은 코드가 생성되면 오버 헤드가 발생할 수 있습니다.
그만큼ILGenerator
팩토리에 대한 코드를 동적으로 생성합니다.
지도의 일부 또는Dictionary
이미 사용한 유형의 유형을 만들고 해당 유형에 대해 생성 된 팩토리 메소드를 유지합니다.
대리자를 생성하고 생성자를 직접 호출하는 일반적인 방법입니다. 제공된 대리자 형식의 서명을 사용하여 지정된 형식의 생성자를 자동으로 검색하고 해당 형식의 대리자를 만듭니다. 여기 코드 :
/// <summary>
/// Reflective object construction helper.
/// All methods are thread safe.
/// </summary>
public static class Constructor
{
/// <summary>
/// Searches an instanceType constructor with delegateType-matching signature and constructs delegate of delegateType creating new instance of instanceType.
/// Instance is casted to delegateTypes's return type.
/// Delegate's return type must be assignable from instanceType.
/// </summary>
/// <param name="delegateType">Type of delegate, with constructor-corresponding signature to be constructed.</param>
/// <param name="instanceType">Type of instance to be constructed.</param>
/// <returns>Delegate of delegateType wich constructs instance of instanceType by calling corresponding instanceType constructor.</returns>
public static Delegate Compile(Type delegateType,Type instanceType)
{
if (!typeof(Delegate).IsAssignableFrom(delegateType))
{
throw new ArgumentException(String.Format("{0} is not a Delegate type.",delegateType.FullName),"delegateType");
}
var invoke = delegateType.GetMethod("Invoke");
var parameterTypes = invoke.GetParameters().Select(pi => pi.ParameterType).ToArray();
var resultType = invoke.ReturnType;
if(!resultType.IsAssignableFrom(instanceType))
{
throw new ArgumentException(String.Format("Delegate's return type ({0}) is not assignable from {1}.",resultType.FullName,instanceType.FullName));
}
var ctor = instanceType.GetConstructor(
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, parameterTypes, null);
if(ctor == null)
{
throw new ArgumentException("Can't find constructor with delegate's signature","instanceType");
}
var parapeters = parameterTypes.Select(Expression.Parameter).ToArray();
var newExpression = Expression.Lambda(delegateType,
Expression.Convert(Expression.New(ctor, parapeters), resultType),
parapeters);
var @delegate = newExpression.Compile();
return @delegate;
}
public static TDelegate Compile<TDelegate>(Type instanceType)
{
return (TDelegate) (object) Compile(typeof (TDelegate), instanceType);
}
}
의 일부입니다Yappi프로젝트의 출처. 이것을 사용하여 매개 변수가있는 생성자 (ref 및 out 매개 변수 제외)를 포함하여 지정된 유형의 모든 생성자를 호출하는 대리자를 생성 할 수 있습니다.
샘플 사용법 :
var newList = Constructor.Compile<Func<int, IList<String>>>(typeof (List<String>));
var list = newList(100);
대리자를 만든 후 정적 사전이나 generic 매개 변수가있는 클래스의 정적 필드에 어딘가에 저장합니다. 매번 새로운 대리인을 구성하지 마십시오. 주어진 유형의 여러 인스턴스를 구성하는 데 하나의 대리자를 사용하십시오.
CreateInstance
- 그게 핵심은 당신이 전화하고 있기 때문이야.CreateInstance
한 번 그러나 그 때생각해 내다공장 대표. 전화를 거는 경우CreateInstance
각 작업마다 다음 예, 느려질 수 있습니다 ... - Jon Skeet