.net 类型描述提供器

.net 类型描述提供器,主要功能:

  • 链式枚举类型中的属性,数据绑定(尤其是绑定对象中含有聚合对象的时候)的时候非常有用
  • 快速访问类型中的属性,提供数据绑定效率  (参考:http://www.codeproject.com/Articles/18450/HyperDescriptor-Accelerated-dynamic-property-acces)

how to use :

  [TypeDescriptionProvider(typeof(HyperTypeDescriptionProvider))]
    public class User
    {
        public int Id
        {
            get;
            set;
        }

        public string Name
        {
            get;
            set;
        }

        public Security MySecurity
        {
            get;
            set;
        }


    }

    public class Security 
    {
        public string Isin
        {
            get;
            set;
        }

        public DateTime MaturityDate
        {
            get;
            set;
        }
    
    }

       

Check what you will see :

static void Main(string[] args)
        {

            PropertyDescriptorCollection col = TypeDescriptor.GetProperties(typeof(User));

            foreach (PropertyDescriptor item in col)
            {
                Console.WriteLine(item.Name, item.Category);
            }

            Console.ReadLine();

        }



source code begins here:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;

namespace ConsoleApplication1.HyperDescriptor
{
    public class HyperTypeDescriptor : CustomTypeDescriptor
    {
        private static int s_counter;
        private static readonly Dictionary s_propertyDescriptors;
        private static readonly ModuleBuilder s_moduleBuilder;
        private static readonly Type s_reflectPropertyDescriptorType;
     
        private  readonly PropertyDescriptorCollection m_propertyDescriptorCollection;

        static HyperTypeDescriptor()
        {
            s_propertyDescriptors = new Dictionary();
            s_reflectPropertyDescriptorType = Assembly.GetAssembly(typeof(PropertyDescriptor)).GetType("System.ComponentModel.ReflectPropertyDescriptor");

            AssemblyName an = new AssemblyName("Hyper.ComponentModel.dynamic");
            AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
            s_moduleBuilder = ab.DefineDynamicModule("Hyper.ComponentModel.dynamic.dll");


        }

        internal  HyperTypeDescriptor(ICustomTypeDescriptor parent)
            :base(parent)
        {
            m_propertyDescriptorCollection = WrapProperties(parent.GetProperties());
        }


        public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
        {
            return m_propertyDescriptorCollection;
        }

        public override PropertyDescriptorCollection GetProperties()
        {
            return m_propertyDescriptorCollection;
        }

        private static PropertyDescriptorCollection WrapProperties(PropertyDescriptorCollection oldProps)
        {

            var newProps = new List();
            var changed = false;
            //HACK:how to identify reflection,given the class internal
            foreach (PropertyDescriptor oldProp in oldProps)
            {
                var pd = oldProp;
                if (ReferenceEquals(s_reflectPropertyDescriptorType, pd.GetType()) && TryCreatePropertyDescriptor(ref pd))
                    changed = true;
                newProps.Add(pd);
                AddChildDescriptors(newProps, pd);
            }

            return changed ? new PropertyDescriptorCollection(newProps.ToArray(), true) : oldProps;
        
        
        }

        private static void AddChildDescriptors(List newProps, PropertyDescriptor pd)
        {
            var  type = pd.PropertyType;
            //don't expand properties for standard .net types
            if ("CommonLanguageRuntimeLibrary".Equals(type.Module.ScopeName, StringComparison.OrdinalIgnoreCase))
                return;
            var properties = TypeDescriptor.GetProperties(type);
            foreach (PropertyDescriptor p in properties)
            {
                var pp = new PathPropertyDescriptor(pd, p);

                newProps.Add(pp);
            }
        }

        private static bool TryCreatePropertyDescriptor(ref PropertyDescriptor descriptor)
        {
            try
            {
                PropertyInfo property = descriptor.ComponentType.GetProperty(descriptor.Name);
                if (property == null) return false;

                lock (s_propertyDescriptors)
                {
                    PropertyDescriptor foundBuiltAlready;
                    if (s_propertyDescriptors.TryGetValue(property, out foundBuiltAlready))
                    {
                        descriptor = foundBuiltAlready;
                        return true;
                    }

                    string name = "_c" + Interlocked.Increment(ref s_counter).ToString();
                    TypeBuilder tb = s_moduleBuilder.DefineType(name, 
                        TypeAttributes.Sealed | TypeAttributes.NotPublic 
                        | TypeAttributes.Class | TypeAttributes.BeforeFieldInit 
                        | TypeAttributes.AutoClass | TypeAttributes.Public, 
                        typeof(ChainingPropertyDescriptor));

                    // ctor calls base
                    ConstructorBuilder cb = tb.DefineConstructor(MethodAttributes.HideBySig | 
                        MethodAttributes.Public | MethodAttributes.SpecialName |
                        MethodAttributes.RTSpecialName,
                        CallingConventions.Standard, new Type[] { typeof(PropertyDescriptor) });
                    ILGenerator il = cb.GetILGenerator();
                    il.Emit(OpCodes.Ldarg_0);
                    il.Emit(OpCodes.Ldarg_1);
                    il.Emit(OpCodes.Call, 
                        typeof(ChainingPropertyDescriptor).GetConstructor(
                        BindingFlags.NonPublic 
                        | BindingFlags.Instance, null, 
                        new Type[] { typeof(PropertyDescriptor) }, null));
                    il.Emit(OpCodes.Ret);

                    MethodBuilder mb;
                    MethodInfo baseMethod;
                    if (property.CanRead)
                    {
                        // obtain the implementation that we want to override
                        baseMethod = typeof(ChainingPropertyDescriptor).GetMethod("GetValue");
                        // create a new method that accepts an object and returns an object (as per the base)
                        mb = tb.DefineMethod(baseMethod.Name,
                            MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final,
                            baseMethod.CallingConvention, baseMethod.ReturnType, new Type[] { typeof(object) });
                        // start writing IL into the method
                        il = mb.GetILGenerator();
                        if (property.DeclaringType.IsValueType)
                        {
                            // upbox the object argument into our known (instance) struct type
                            LocalBuilder lb = il.DeclareLocal(property.DeclaringType);
                            il.Emit(OpCodes.Ldarg_1);
                            il.Emit(OpCodes.Unbox_Any, property.DeclaringType);
                            il.Emit(OpCodes.Stloc_0);
                            il.Emit(OpCodes.Ldloca_S, lb);
                        }
                        else
                        {
                            // cast the object argument into our known class type
                            il.Emit(OpCodes.Ldarg_1);
                            il.Emit(OpCodes.Castclass, property.DeclaringType);
                        }
                        // call the "get" method
                        il.Emit(OpCodes.Callvirt, property.GetGetMethod());

                        if (property.PropertyType.IsValueType)
                        {
                            // box it from the known (value) struct type
                            il.Emit(OpCodes.Box, property.PropertyType);
                        }
                        // return the value
                        il.Emit(OpCodes.Ret);
                        // signal that this method should override the base
                        tb.DefineMethodOverride(mb, baseMethod);
                    }

                    bool supportsChangeEvents = descriptor.SupportsChangeEvents, isReadOnly = descriptor.IsReadOnly;

                    // override SupportsChangeEvents
                    baseMethod = typeof(ChainingPropertyDescriptor).GetProperty("SupportsChangeEvents").GetGetMethod();
                    mb = tb.DefineMethod(baseMethod.Name, MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.SpecialName, baseMethod.CallingConvention, baseMethod.ReturnType, Type.EmptyTypes);
                    il = mb.GetILGenerator();
                    if (supportsChangeEvents)
                    {
                        il.Emit(OpCodes.Ldc_I4_1);
                    }
                    else
                    {
                        il.Emit(OpCodes.Ldc_I4_0);
                    }
                    il.Emit(OpCodes.Ret);
                    tb.DefineMethodOverride(mb, baseMethod);

                    // override IsReadOnly
                    baseMethod = typeof(ChainingPropertyDescriptor).GetProperty("IsReadOnly").GetGetMethod();
                    mb = tb.DefineMethod(baseMethod.Name, MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.SpecialName, baseMethod.CallingConvention, baseMethod.ReturnType, Type.EmptyTypes);
                    il = mb.GetILGenerator();
                    if (isReadOnly)
                    {
                        il.Emit(OpCodes.Ldc_I4_1);
                    }
                    else
                    {
                        il.Emit(OpCodes.Ldc_I4_0);
                    }
                    il.Emit(OpCodes.Ret);
                    tb.DefineMethodOverride(mb, baseMethod);

                    /*  REMOVED: PropertyType, ComponentType; actually *adds* time overriding these
                    // override PropertyType
                    baseMethod = typeof(ChainingPropertyDescriptor).GetProperty("PropertyType").GetGetMethod();
                    mb = tb.DefineMethod(baseMethod.Name, MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.SpecialName, baseMethod.CallingConvention, baseMethod.ReturnType, Type.EmptyTypes);
                    il = mb.GetILGenerator();
                    il.Emit(OpCodes.Ldtoken, descriptor.PropertyType);
                    il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));
                    il.Emit(OpCodes.Ret);
                    tb.DefineMethodOverride(mb, baseMethod);

                    // override ComponentType
                    baseMethod = typeof(ChainingPropertyDescriptor).GetProperty("ComponentType").GetGetMethod();
                    mb = tb.DefineMethod(baseMethod.Name, MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.SpecialName, baseMethod.CallingConvention, baseMethod.ReturnType, Type.EmptyTypes);
                    il = mb.GetILGenerator();
                    il.Emit(OpCodes.Ldtoken, descriptor.ComponentType);
                    il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));
                    il.Emit(OpCodes.Ret);
                    tb.DefineMethodOverride(mb, baseMethod);
                    */

                    // for classes, implement write (would be lost in unbox for structs)
                    if (!property.DeclaringType.IsValueType)
                    {
                        if (!isReadOnly && property.CanWrite)
                        {
                            // override set method
                            baseMethod = typeof(ChainingPropertyDescriptor).GetMethod("SetValue");
                            mb = tb.DefineMethod(baseMethod.Name, MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final, baseMethod.CallingConvention, baseMethod.ReturnType, new Type[] { typeof(object), typeof(object) });
                            il = mb.GetILGenerator();
                            il.Emit(OpCodes.Ldarg_1);
                            il.Emit(OpCodes.Castclass, property.DeclaringType);
                            il.Emit(OpCodes.Ldarg_2);
                            if (property.PropertyType.IsValueType)
                            {
                                il.Emit(OpCodes.Unbox_Any, property.PropertyType);
                            }
                            else
                            {
                                il.Emit(OpCodes.Castclass, property.PropertyType);
                            }
                            il.Emit(OpCodes.Callvirt, property.GetSetMethod());
                            il.Emit(OpCodes.Ret);
                            tb.DefineMethodOverride(mb, baseMethod);
                        }

                        if (supportsChangeEvents)
                        {
                            EventInfo ei = property.DeclaringType.GetEvent(property.Name + "Changed");
                            if (ei != null)
                            {
                                baseMethod = typeof(ChainingPropertyDescriptor).GetMethod("AddValueChanged");
                                mb = tb.DefineMethod(baseMethod.Name, MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.SpecialName, baseMethod.CallingConvention, baseMethod.ReturnType, new Type[] { typeof(object), typeof(EventHandler) });
                                il = mb.GetILGenerator();
                                il.Emit(OpCodes.Ldarg_1);
                                il.Emit(OpCodes.Castclass, property.DeclaringType);
                                il.Emit(OpCodes.Ldarg_2);
                                il.Emit(OpCodes.Callvirt, ei.GetAddMethod());
                                il.Emit(OpCodes.Ret);
                                tb.DefineMethodOverride(mb, baseMethod);

                                baseMethod = typeof(ChainingPropertyDescriptor).GetMethod("RemoveValueChanged");
                                mb = tb.DefineMethod(baseMethod.Name, MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.SpecialName, baseMethod.CallingConvention, baseMethod.ReturnType, new Type[] { typeof(object), typeof(EventHandler) });
                                il = mb.GetILGenerator();
                                il.Emit(OpCodes.Ldarg_1);
                                il.Emit(OpCodes.Castclass, property.DeclaringType);
                                il.Emit(OpCodes.Ldarg_2);
                                il.Emit(OpCodes.Callvirt, ei.GetRemoveMethod());
                                il.Emit(OpCodes.Ret);
                                tb.DefineMethodOverride(mb, baseMethod);
                            }
                        }

                    }
                    PropertyDescriptor newDesc = tb.CreateType().GetConstructor(new Type[] { typeof(PropertyDescriptor) }).Invoke(new object[] { descriptor }) as PropertyDescriptor;
                    if (newDesc == null)
                    {
                        return false;
                    }
                    descriptor = newDesc;
                    s_propertyDescriptors.Add(property, descriptor);
                    return true;
                }
            }
            catch (Exception ex)
            {
                return false;
            }
        }

    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Security.Permissions;

namespace ConsoleApplication1.HyperDescriptor
{
    public class HyperTypeDescriptionProvider : TypeDescriptionProvider
    {

        private static readonly IDictionary
            s_descriptors = new Dictionary();

        public HyperTypeDescriptionProvider()
            : this(typeof(object))
        {

        }

        public HyperTypeDescriptionProvider(Type type)
            : this(TypeDescriptor.GetProvider(type))
        {

        }

        public HyperTypeDescriptionProvider(TypeDescriptionProvider parent)
            : base(parent)
        {

        }

        public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
        {
            lock (s_descriptors)
            {
                ICustomTypeDescriptor descriptor;
                if (!s_descriptors.TryGetValue(objectType, out descriptor))
                {
                    try
                    {
                        descriptor = BuildDescriptor(objectType);
                    }
                    catch (Exception)
                    {

                        return base.GetTypeDescriptor(objectType, instance);
                    }
                }

                return descriptor;
            }
        }


        //[ReflectionPermission(SecurityAction.Assert, Flags = ReflectionPermissionFlag.AllFlags)]
        [ReflectionPermission(SecurityAction.Assert, Unrestricted=true)]
        private ICustomTypeDescriptor BuildDescriptor(Type objectType)
        {
            // NOTE: "descriptors" already locked here

            // get the parent descriptor and add to the dictionary so that
            // building the new descriptor will use the base rather than recursing
            ICustomTypeDescriptor descriptor = base.GetTypeDescriptor(objectType, null);
            s_descriptors.Add(objectType, descriptor);
            try
            {
                // build a new descriptor from this, and replace the lookup
                descriptor = new HyperTypeDescriptor(descriptor);
                s_descriptors[objectType] = descriptor;
                return descriptor;
            }
            catch
            {   // rollback and throw
                // (perhaps because the specific caller lacked permissions;
                // another caller may be successful)
                s_descriptors.Remove(objectType);
                throw;
            }
        }

    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace ConsoleApplication1.HyperDescriptor
{
    public class PathPropertyDescriptor : PropertyDescriptor
    {
        private readonly PropertyDescriptor m_propertry;
        private readonly PropertyDescriptor m_root;
        private PropertyDescriptor pd;
        private object p;

        public PathPropertyDescriptor(PropertyDescriptor root,  PropertyDescriptor property)
            : base(string.Format("{0}.{1}", root.Name, property.Name), null)
        {
            m_propertry = property;
            m_root = root;
        }

    


        public override bool CanResetValue(object component)
        {
            return false;
        }

        public override Type ComponentType
        {
            get
            {
                return m_propertry.ComponentType;
            }
        }

     
        public override bool IsReadOnly
        {
            get
            {
                return m_propertry.IsReadOnly;
            }
        }

        public override Type PropertyType
        {
            get {
                return m_propertry.PropertyType;
            }
        }


        public override string Description
        {
            get
            {
                return m_propertry.Description;
            }
        }

        public override string DisplayName
        {
            get
            {
                return m_propertry.DisplayName;
            }
        }


        public override object GetValue(object component)
        {
            var root = m_root.GetValue(component);

            return root == null ? root : m_propertry.GetValue(root);

        }


        public override void SetValue(object component, object value)
        {
            var root = m_root.GetValue(component);
            if (root != null)
                m_propertry.SetValue(root, value);
        }

        public override bool ShouldSerializeValue(object component)
        {
            return false;
        }

        public override void ResetValue(object component)
        {
            //do nothing
        }
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace ConsoleApplication1.HyperDescriptor
{
    public abstract class ChainingPropertyDescriptor : PropertyDescriptor
    {
        private readonly PropertyDescriptor m_root;

        protected ChainingPropertyDescriptor(PropertyDescriptor root)
            : base(root)
        {
            m_root = root;
        }

        protected PropertyDescriptor Root
        {
            get {
                return m_root;
            }
        }
        public override AttributeCollection Attributes
        {
            get
            {
                return m_root.Attributes;
            }
        }

        public override string Category
        {
            get
            {
                return m_root.Category;
            }
        }


        public override Type ComponentType
        {
            get {
                return m_root.ComponentType;
            }

        }

        public override TypeConverter Converter
        {
            get
            {
                return Root.Converter;
            }
        }

        public override string Description
        {
            get
            {
                return m_root.Description;
            }
        }

        public override bool DesignTimeOnly
        {
            get
            {
                return m_root.DesignTimeOnly;
            }
        }

        public override string DisplayName
        {
            get
            {
                return m_root.DisplayName;
            }
        }

        public override bool IsBrowsable
        {
            get
            {
                return m_root.IsBrowsable;
            }
        }

        public override bool IsLocalizable
        {
            get
            {
                return m_root.IsLocalizable;
            }
        }

        public override bool IsReadOnly
        {
            get {
                return m_root.IsReadOnly;
            }
        }

        public override string Name
        {
            get
            {
                return m_root.Name;
            }
        }

        public override Type PropertyType
        {
            get {
                return m_root.PropertyType;
            }
        }

        public override bool SupportsChangeEvents
        {
            get
            {
                return m_root.SupportsChangeEvents;
            }
        }

        public override void AddValueChanged(object component, EventHandler handler)
        {
            m_root.AddValueChanged(component, handler);
        }

        public override bool CanResetValue(object component)
        {
            return m_root.CanResetValue(component);
        }

        public override bool Equals(object obj)
        {
            return m_root.Equals(obj);
        }

        public override PropertyDescriptorCollection GetChildProperties(object instance, Attribute[] filter)
        {
            return m_root.GetChildProperties(instance, filter);
        }

        public override object GetEditor(Type editorBaseType)
        {
            return m_root.GetEditor(editorBaseType);
        }

        public override int GetHashCode()
        {
            return m_root.GetHashCode();
        }

        public override object GetValue(object component)
        {
            return m_root.GetValue(component);
        }

        public override void RemoveValueChanged(object component, EventHandler handler)
        {
            m_root.RemoveValueChanged(component, handler);
        }

        public override void ResetValue(object component)
        {
            m_root.ResetValue(component);
        }

        public override void SetValue(object component, object value)
        {
            m_root.SetValue(component, value);
        }

        public override bool ShouldSerializeValue(object component)
        {
            return m_root.ShouldSerializeValue(component);
        }

        public override string ToString()
        {
            return m_root.ToString();
        }

    }
}


你可能感兴趣的:(Microsoft,.NET)