简体   繁体   English

从GUID获取类型

[英]Get type from GUID

For various reasons, I need to implement a type caching mechanism in C#. 由于各种原因,我需要在C#中实现类型缓存机制。 Fortunately, the CLR provides Type.GUID to uniquely identify a type. 幸运的是,CLR提供Type.GUID来唯一标识一个类型。 Unfortunately, I can't find any way to look up a type based on this GUID. 不幸的是,我找不到任何方法来查找基于此GUID的类型。 There's Type.GetTypeFromCLSID() but based on my understanding of the documentation (and experiments) that does something very, very different. Type.GetTypeFromCLSID()但基于我对文档(和实验)的理解,它们做了非常非常不同的事情。

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? 是否有任何方法可以获得基于其GUID的类型,而不是循环遍历所有已加载的类型并与其GUID进行比较?

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. 编辑 :我忘了提到我真的很喜欢固定宽度的“类型指纹”,这就是为什么GUID对我这么有吸引力。 In a general case, of course, the fully qualified name of the type would work. 当然,在一般情况下,该类型的完全限定名称可以使用。

why not use the designated property for that, ie. 为什么不使用指定的财产,即。 AssemblyQualifiedName ? AssemblyQualifiedName This property is documented as "can be persisted and later used to load the Type". 此属性记录为“可以持久化并稍后用于加载类型”。

The GUID is for COM interop. GUID用于COM互操作。

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. 这可能只是已经发布的答案的摘要,但我认为没有首先构建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. 处理AssemblyLoad事件会处理动态加载的程序集。

From what I understand, Type.GUID uses the assembly version of the type as part of the Guid generation algorithm. 据我所知,Type.GUID使用该类型的程序集版本作为Guid生成算法的一部分。 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. 根据您的应用程序,使用另一个答案中描述的GetDeterministicGuid方法可能是可取的。

Don't loop to compare. 不要循环比较。 Populate a Dictionary<Type> and use the Contains method. 填充Dictionary<Type>并使用Contains方法。

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). 这肯定会给你一个固定大小的条目,因为它们都是对象引用(Type的实例基本上是工厂对象)。

What about (from Generating Deterministic GUIDs ): 那么(来自Generating Deterministic GUID ):

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 . 并抛出那个typeof().AssemblyQualifiedName You could to store this data inside a Dictionary<string, Guid> collection (or, whatever, a <Guid, string> ). 您可以将此数据存储在Dictionary<string, Guid>集合中(或者,无论如何, <Guid, string> )。

This way you'll have always a same GUID for a given type (warning: collision is possible). 这样,对于给定类型,您将始终具有相同的GUID (警告:可能发生冲突)。

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. 您可以使用Visual Studio,Tools-> Create Guid生成GUID。

The Mono documentation reports that a module has a Metadata heap of guids . Mono文档报告模块具有guane元数据堆

Perhaps Cecil might help you lookup a type based on its guid? 也许Cecil可能会帮助您根据其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? 不过不确定,有一个GuidHeap类,它似乎正在生成guid,但也许这足以让你的缓存工作?

I would use the typeof (class).GUID to find the instance in the cache dictionary: 我会使用typeof(class).GUID来查找缓存字典中的实例:

private Dictionary<Guid, class> cacheDictionary { get; set; }

and I would have a method to return the dictionary and the GUID as parameter of the method to search for the class in the dictionary. 我会有一个方法返回字典和GUID作为方法的参数来搜索字典中的类。

public T Getclass<T>()
    {
        var key = typeof(T).GUID;
        var foundClass= cacheDictionary.FirstOrDefault(x => x.Key == key);
        T item;
        if (foundClass.Equals(default(KeyValuePair<Guid, T>)))
        {
            item = new T()
            cacheDictionary.Add(key, item);
        }
        else
            item = result.Value;

        return item;
    }

and I would use a singleton pattern for the cache, 我会使用单例模式进行缓存,

and the call would be something like the code below: 并且调用将类似于下面的代码:

   var cachedObject = Cache.Instance.Getclass<class>();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM