Dotnet专业组件开发揭密(三)

Dotnet专业组件开发揭密(三)

--TypeDescriptor内部机制及其应用(下)

前面文章里我们TypeDescriptor是用来返回一个类的属性或事件描述符的,VS中使用的PropertyGrid就是通过它来取得一个类的属性的。而不是我们以为的是通过反射来做的。那么它的内部机制是如何的?

TypeDescriptor它会进行几个判别,一是查看类是否实现了ICustomTypeDescriptor接口,如果没实现,它会通过反射来取得属性,如果实现,则用接口来取得。具体原理图如下:

 

Dotnet专业组件开发揭密(三)

    二是它会查看这个类有没有相应的类信息描述提供者,它是通过一个内部哈希表,每个元素指向一个TypeDescriptionProvider。有意思的是这个内部哈希表是一个弱引用哈希表,它的内部名称叫(WeakHashTable),它会根据系统内存的情况来调整内存使用,它的键可以是具体的类实例,也可以是类本身。TypeDescriptor就是通过查看这个哈希表来取得对应的提供者,然后由提供者来对得属性。具体的原理图见下:

 

 

Dotnet专业组件开发揭密(三)

下面是TypeDescriptor的GetProperties方法其内部流程的伪代码(根据Reflector反汇编代码改成),大家可以仔细看看下面的注释,更加有利于了解TypeDescriptor的运作机制

public static PropertyDescriptorCollection GetProperties(object component,bool noCustomTypeDesc)

{

    ICollection c1; 

   

/*此行代码它有两个功能

第一步查看TypeDescriptor内部的一个的WeakHashtable表,它是一个哈希表,每个元素是一个TypeDescriptorNode的类实例,这个类继承于TypeDescriptorProvider。对于传入的component,会用它作哈希表的KEY来检测对应的TypeDescriptorProvider,如果传入的是Type类型,则先检测它是否一个Com接口类,如果是就取得默认的COM类的提供者,否则的话就用Type作为KEY来检测这个哈希表。

第二步如果此表登记有自定义的Provider,则利用这个Provider来取得一个用户自定义的CustomTypeDescriptor,否则提供一个由反射来取得类信息的默认的Descripor

*/

ICustomTypeDescriptor descriptor = GetDescriptor(component, noCustomTypeDesc);

   

    //判断是否类本身实现了IcustomTypeDescriptor接口

if (component is ICustomTypeDescriptor)

    {

        //通过类型描述符取类的属性

c1 = descriptor.GetProperties() ;

        if (noCustomTypeDesc) //是否返回类本身自定义的属性

        {

            /*取扩展类型描述符

            这里同样有很复杂的实现,俺是转了半天才看懂,它大概的原理是在CLR内部实现了一个DefaultExtendTypeDesriptor的类,它同样是实现了ICustomTypeDescriptor接口的

*/

            ICustomTypeDescriptor exDescriptor = GetExtendDescriptor(component);

            if (extendedDescriptor != null)

            {

                /*

                这里CLR的实现很关键,这里就实现了如何使实现了IextenderProvider的类可以动态地给已有类加上属性。它实际上内部有一个叫ReflectTypeDescriptionProvider的提供者,GetProperties这个方法首先会查看这个类是否有Icomponent接口,如果它就找到Site,然后通过Site找到Container,也就是组件的逻辑容器,然后查看逻辑容器里的组件是否有实现IextenderProvider接口的,如果有就找出来,把它扩展的属性加到这个类上。

*/

                ICollection c2 = extendedDescriptor.GetProperties() ;

                //合并两种情况所取得的属性集合

                c1 = PipelineMerge(c1, c2, component);

            }

        }

    }

    else

    {

        //返回每个类的相关信息的Cache

        IDictionary cache = GetCache(component);

        c1 = descriptor.GetProperties();

        c1 = PipelineInitialize(1, c1, cache); //用新的属性信息来填充这个Cache

        ICustomTypeDescriptor descriptor3 = GetExtendedDescriptor(component);

        if (descriptor3 != null)

        {

            ICollection c3 = descriptor3.GetProperties();

            c1 = PipelineMerge(1, c1, c3, component, cache);

        }

    }

   

    return c1 as PropertyDescriptorCollection;

   

}

作为System.Component命名空间下最重要的类之一,TypeDescriptor其内部实现相当复杂,虽然VS本身使用相当它频繁,但是一般开发人员很少用到它,正因如此无论网上或是书本都少提及它。但如果你要理解VS环境很多奇怪的机制和现象,却不得不去了解它,这连续几篇文章均只是浅浅地探索了它的一部分功能和奥秘,更多的宝藏需要你自已深入挖掘。

你可能感兴趣的:(net)