Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get type from GUID

For various reasons, I need to implement a type caching mechanism in C#. Fortunately, the CLR provides Type.GUID to uniquely identify a type. Unfortunately, I can't find any way to look up a type based on this GUID. There's Type.GetTypeFromCLSID() but based on my understanding of the documentation (and experiments) that does something very, very different.

Is there any way to get a type based on its GUID short of looping through all the loaded types and comparing to their GUIDs?

EDIT: I forgot to mention that I would really like a "type fingerprint" of fixed width, that's why the GUID is so appealing to me. In a general case, of course, the fully qualified name of the type would work.

like image 481
Tamas Czinege Avatar asked Jan 12 '10 00:01

Tamas Czinege


4 Answers

This may just be a summary of answers already posted, but I don't think there is a way to do this without first building a map of Guid->Type.

We do this in our framework on initialization:

static TypeManager()
    {
        AppDomain.CurrentDomain.AssemblyLoad += (s, e) =>
        {
            _ScanAssembly(e.LoadedAssembly);
        };

        foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
        {
            _ScanAssembly(a);
        }
    }

    private static void _ScanAssembly(Assembly a)
    {
        foreach (Type t in a.GetTypes())
        {
           //optional check to filter types (by interface or attribute, etc.)
           //Add type to type map   
        }
    }

Handling the AssemblyLoad event takes care of dynamically loaded assemblies.

From what I understand, Type.GUID uses the assembly version of the type as part of the Guid generation algorithm. This may lead to trouble if you increment your assembly version numbers. Using the GetDeterministicGuid method described in another answer would probably be advisable, depending on your application.

like image 117
Joe Enzminger Avatar answered Nov 02 '22 22:11

Joe Enzminger


Don't loop to compare. Populate a Dictionary<Type> and use the Contains method.

Dictionary<Type> types = new Dictionary<Types>();
... //populate 

if (types.Contains(someObject.GetType())) 
  //do something

This will certainly give you a fixed size entry, since all of them will be object references (instances of Type essentially being factory objects).

like image 41
Peter Wone Avatar answered Nov 02 '22 22:11

Peter Wone


why not use the designated property for that, ie. AssemblyQualifiedName? This property is documented as "can be persisted and later used to load the Type".

The GUID is for COM interop.

like image 7
Remus Rusanu Avatar answered Nov 02 '22 23:11

Remus Rusanu


What about (from Generating Deterministic GUIDs):

private Guid GetDeterministicGuid(string input)
{
    // use MD5 hash to get a 16-byte hash of the string:
    MD5CryptoServiceProvider provider = new MD5CryptoServiceProvider();
    byte[] inputBytes = Encoding.Default.GetBytes(input);
    byte[] hashBytes = provider.ComputeHash(inputBytes);

    // generate a guid from the hash:
    Guid hashGuid = new Guid(hashBytes);
    return hashGuid;
}

And throw in that typeof().AssemblyQualifiedName. You could to store this data inside a Dictionary<string, Guid> collection (or, whatever, a <Guid, string>).

This way you'll have always a same GUID for a given type (warning: collision is possible).

like image 1
Rubens Farias Avatar answered Nov 02 '22 22:11

Rubens Farias