Dekodowanie RuntimeType.InvokeMember
daje ten fragment:
if ((bindingFlags & BindingFlags.CreateInstance) != BindingFlags.Default)
{
if (((bindingFlags & BindingFlags.CreateInstance) != BindingFlags.Default) && ((bindingFlags & (BindingFlags.SetProperty | BindingFlags.GetProperty | BindingFlags.SetField | BindingFlags.GetField | BindingFlags.InvokeMethod)) != BindingFlags.Default))
{
throw new ArgumentException(Environment.GetResourceString("Arg_CreatInstAccess"), "bindingFlags");
}
return Activator.CreateInstance(this, bindingFlags, binder, providedArgs, culture);
}
Innymi słowy, InvokeMember
z tymi BindingFlags
wzywa Activator.CreateInstance
. Przechodzi przez kilka kolejnych warstw wywołań (sprawdzanie powiązań, sprawdzanie argumentów) przed przejściem do biznesu. Activator.CreateInstance<T>
jest bardziej zwięzły:
public static T CreateInstance<T>()
{
bool bNeedSecurityCheck = true;
bool canBeCached = false;
RuntimeMethodHandle emptyHandle = RuntimeMethodHandle.EmptyHandle;
return (T) RuntimeTypeHandle.CreateInstance(typeof(T) as RuntimeType, true, true, ref canBeCached, ref emptyHandle, ref bNeedSecurityCheck);
}
EDITED Można oczekiwać, że ten ostatni będzie szybciej, ale to metoda zwana RuntimeType.CreateInstanceSlow
RuntimeTypeHandle.CreateInstance
wzywa również do pracy; jest używany jako rezerwowy, jeśli nie można znaleźć pozycji pamięci podręcznej programu Activator dla konstruktora. Zrobiłbym test wydajności, jeśli szukasz najszybszego rozwiązania z tych dwóch.
FWIW: 'Activator.CreateInstance()' jest bardziej poprawne dla twojego pierwszego przykładu, ponieważ nie będzie wymagało rzutowania wyniku na 'T'. –
@Steve Guidi: Dzięki. Zaktualizuję pytanie. –