Because he does more work @JJS. Remember your training and use the source, Luke.
The documentation gives some tips. Type.GetType (String) Method
- If the type is in the assembly known to your program at compile time, it is more efficient to use it in C #, GetType in Visual Basic or C ++.
- If typeName contains a namespace but not the assembly name, this method searches only the assembly of the calling object and Mscorlib.dll in that order.
we know that typeof(T) is a call that compiled into ldtoken and GetTypeFromHandle , but what does GetTypeFromHandle do compared to GetTypeByName ?
First let's resolve the simple one. GetTypeFromHandle defined as
[Pure] [System.Security.SecuritySafeCritical]
Lets get the CLR version that we can reference.
Common Version Common Language Infrastructure 2.0 Release
runtimehandles.cpp
FCIMPL1(Object*, RuntimeTypeHandle::GetRuntimeType, void* th) { CONTRACTL { THROWS; DISABLED(GC_TRIGGERS); MODE_COOPERATIVE; SO_TOLERANT; } CONTRACTL_END; OBJECTREF refType = NULL; TypeHandle typeHandle = TypeHandle::FromPtr(th); TypeHandle* pTypeHandle = &typeHandle; _ASSERTE(CheckPointer(pTypeHandle)); _ASSERTE(CheckPointer(pTypeHandle->AsPtr(), NULL_OK)); if (pTypeHandle->AsPtr() == NULL) return NULL; refType = pTypeHandle->GetManagedClassObjectIfExists(); if (refType != NULL) return OBJECTREFToObject(refType); HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_1(Frame::FRAME_ATTR_RETURNOBJ, refType); refType = pTypeHandle->GetManagedClassObject(); HELPER_METHOD_FRAME_END(); return OBJECTREFToObject(refType); } FCIMPLEND
Good. It is legal. We make an evil simple call here to get an OBJECTREFToObject.
No search, just looking at the type efficiently using the method table. Need to upgrade .NET internals ?
OK, what about the slow method? Type.GetType (String) Method
Change the call stack and find out that it is calling RuntimeTypeHandle.GetTypeByName
[System.Security.SecurityCritical]
runtimehandles.cpp
FCIMPL6(EnregisteredTypeHandle, RuntimeTypeHandle::GetTypeByName, StringObject* classNameUNSAFE, CLR_BOOL bThrowOnError, CLR_BOOL bIgnoreCase, CLR_BOOL bReflectionOnly, StackCrawlMark* pStackMark, CLR_BOOL bLoadTypeFromPartialNameHack) { CONTRACTL { THROWS; DISABLED(GC_TRIGGERS); MODE_COOPERATIVE; SO_TOLERANT; } CONTRACTL_END; STRINGREF sRef = (STRINGREF) classNameUNSAFE; TypeHandle typeHandle; HELPER_METHOD_FRAME_BEGIN_RET_1(sRef); { if (!sRef) COMPlusThrowArgumentNull(L"className",L"ArgumentNull_String"); typeHandle = TypeName::GetTypeManaged(sRef->GetBuffer(), NULL, bThrowOnError, bIgnoreCase, bReflectionOnly, FALSE, pStackMark, bLoadTypeFromPartialNameHack); } HELPER_METHOD_FRAME_END(); return typeHandle.AsPtr(); } FCIMPLEND
Ok, but what is TypeName :: GetTypeManaged to do ?!
typeparse.cpp
But it does not stop there
typeparse.cpp
// ------------------------------------------------------------------------------------------------------------- // This is the "uber" GetType() that all public GetType() funnels through. It main job is to figure out which // Assembly to load the type from and then invoke GetTypeHaveAssembly. // // It got a highly baroque interface partly for historical reasons and partly because it the uber-function // for all of the possible GetTypes. // ------------------------------------------------------------------------------------------------------------- /* private instance */ TypeHandle TypeName::GetTypeWorker
It does not stop here.
typeparse.cpp
clsload.cpp
TypeHandle ClassLoader::LoadTypeHandleThrowing(NameHandle* pName, ClassLoadLevel level, Module* pLookInThisModuleOnly) BOOL foundSomething = FindClassModuleThrowing(pName,
// FindClassModuleThrowing detects which module the type you are looking for is in, and loads the module if necessary. // Basically, it iterates through all the assembly modules until a name match is found in the module // AvailableClassHashTable.
if (!typeHnd.IsNull()) { typeHnd = LoadTypeDefThrowing(typeHnd.GetModule(), typeHnd.GetCl(),
// Given the marker indicating the type of Def and the module in which // we interpret this token, we find or load the corresponding type descriptor.
typeHnd = pModule->LookupTypeDef(typeDef, level);
ceeload.h
TypeHandle LookupTypeDef(mdTypeDef token, ClassLoadLevel level = CLASS_LOAD_UNRESTOREDTYPEKEY)
which gives us TypeHandle. We got the same thing in the same GetTypeFromHandle frame stack.
PTR_MethodTable pMT = PTR_MethodTable(GetFromRidMap(&m_TypeDefToMethodTableMap, RidFromToken(token))); if (pMT == NULL || pMT->GetLoadLevel() < level) return TypeHandle(); else return (TypeHandle)pMT;
So ... what is slow? Iterate over FindClassModuleTrowing. It must iterate over the names to find the method table ... Iterating over an array is always slower than finding something with the well-known key available in GetTypeFromHandle
Case is closed.