views:

287

answers:

5
+7  Q: 

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.

+6  A: 

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.

Remus Rusanu
Thanks, but as I mentioned in one of the comments, ideally I would have type "fingerprint" of a fixed width, dealing with variable length strings would make my life a bit more complicated. But yeah, generally if you don't have such a requirement then I agree, the full qualified name is the way to go.
DrJokepu
@Doc: What if you create more than 2^128 types?
Anon.
Anon: Ain't going to happen :) The universe will collapse well before all the computers of the world together can create 2^128 types.
DrJokepu
I'm a bit surprised to hear that variable length poses problems. what data type strcuture you have in mind for the cache that would have problems with a variable length lookup key, in such a high end world as CLR?
Remus Rusanu
Remus Rusanu: Fixed length would be ideal because I need to persist this stuff on the disk and access it quickly. Fixed length data structures mean no need to keep track of a list of offsets as I can find a record easily by knowing the index.
DrJokepu
Variable length fields are blazing fast for an in process relational engine like SQLite.
Remus Rusanu
Well, SQLite is using binary trees for indexing and has to keep track of the offsets of strings to have this working. I'm not saying it's not fast (especially if the OS is caching the disk) but it's at least twice as much effort.
DrJokepu
Are you going to use a buffer pool, read aheads, fancy caching policies like a relational engine does? Is the advantage of easily expressable complex interogation criteria (ie. SQL lanhuage) something that doesn't saves you any development time down the road? I'm not saying use SQLite, but don't dismiss it so easily. A product like that has years of know-how, IO calibration, optimizations and tricks around TLB cache hits and L2 coherency you probably aren't thinking at.
Remus Rusanu
Remus Rusanu: I really don't want to go into the details as they are really out of the scope but I have very good reasons to use the data structures I do and I generally know what I'm doing (at least I'd like to think so). Development time is a secondary concern here. I'd love to talk about it as it is really interesting stuff but I don't think this question is the appropriate medium to do so unfortunately. Thanks for the advice though, generally, you're right, off-the-shelf stuff is most useful most of the time.
DrJokepu
+1  A: 

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).

Peter Wone
Yeah I was considering that... I would still have to pre-populate the dictionary before launching the algorithm and that would add a bit of an overhead to the start-up. I'm no sure how much exactly so I'll do some tests and see if it's feasible to do (it's still better than looping though).
DrJokepu
The hash lookup will be ridiculously more efficient than iterative comparison, so if the comparison happens in a loop it's well worthwhile. But I'd do it anyway for code legibility.
Peter Wone
You could also store a mapping of GUID to qualified name in an efficient data structure (heap or trie). This mapping could already be generated at compile time and be stored in a quickly-to-parse binary format. That could reduce the overhead before launching your algorithm. If you need an actual `Type` object you could create it lazily from the qualified name.
0xA3
divo: Unfortunately the compile time generation is out of question as I will have to deal with types not known at compile time.
DrJokepu
A hash into the class namespace? Interesting. It must be possible, reflection uses it.
Peter Wone
Peter Wone: It would be possible, but then again, I would have to do the same loop/dictionary lookup anyway as hashes are normally unidirectional. I suppose if I kept the hash of the namespace and the unqualified type name separately, that would speed up things a bit.
DrJokepu
I've ran some quick tests and it turned out that building a dictionary of all loaded types is surprisingly quick so I'll go with that approach. Thanks a lot.
DrJokepu
A: 

If you are in control of these classes I would recommend:

public interface ICachable
{
    Guid ClassId { get; }
}

public class Person : ICachable
{
    public Guid ClassId
    {
        get {  return new Guid("DF9DD4A9-1396-4ddb-98D4-F8F143692C45"); }
    }
}

You can generate your GUIDs using Visual Studio, Tools->Create Guid.

Serkan
Thanks, but unfortunately I'm not in control of the types. I must need to be able to deal with any type (well, except for pointers but that's irrelevant to the question).
DrJokepu
Maybe you can combine Dictionary idea and Guids. You can populate it lazily, if type doesn't exist in the dictionary generate a Guid and add it to the dictionary. Use a dictionary key->Type Name, Value->Guid. Some how you need to persist the dictionary, as well I suppose
Serkan
A: 

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).

Rubens Farias
I would still need to do a lookup somehow as this hash mechanism is inherently unidirectional. We're back to the same problem.
DrJokepu
I ran out of bullets: good luck, doc
Rubens Farias
A: 

The Mono documentation reports that a module has a Metadata heap of guids.

Perhaps Cecil might help you lookup a type based on its guid? Not sure though, there is a GuidHeap class, it seems to be generating the guids though, but perhaps this is enough for your cache to work?

Si