namespace Hyper.ComponentModel { using System; using System.Collections.Generic; using System.ComponentModel; using System.Security; using System.Security.Permissions; public sealed class HyperTypeDescriptionProvider : TypeDescriptionProvider { private static readonly Dictionary descriptors = new Dictionary(); private static readonly Dictionary providers = new Dictionary(); public static void Add(Type type) { lock (descriptors) { if (!providers.ContainsKey(type)) { // determine if the base type was already added // if so, remove it before adding sub-type // (if a sub-type is added after its base type, infinite recursion occurs in GetTypeDescriptor()) var baseFound = false; if (type.BaseType != null && providers.ContainsKey(type.BaseType)) { baseFound = true; Remove(type.BaseType); } // add the provider for the type var provider = new HyperTypeDescriptionProvider(TypeDescriptor.GetProvider(type)); TypeDescriptor.AddProvider(provider, type); providers.Add(type, provider); // initialize descriptor provider.GetTypeDescriptor(type); // if base type was removed, we can now add it back after building the sub-type descriptor if (baseFound) Add(type.BaseType); } } } public static void Remove(Type type) { lock (descriptors) { TypeDescriptor.RemoveProvider(providers[type], type); providers.Remove(type); descriptors.Remove(type); } } public static void Clear() { lock (descriptors) { foreach (var provider in providers) TypeDescriptor.RemoveProvider(provider.Value, provider.Key); providers.Clear(); descriptors.Clear(); } } private HyperTypeDescriptionProvider() : this(typeof(object)) { } private HyperTypeDescriptionProvider(Type type) : this(TypeDescriptor.GetProvider(type)) { } private HyperTypeDescriptionProvider(TypeDescriptionProvider parent) : base(parent) { } public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance) { lock (descriptors) { ICustomTypeDescriptor descriptor; if (!descriptors.TryGetValue(objectType, out descriptor)) { try { descriptor = BuildDescriptor(objectType); } catch { return base.GetTypeDescriptor(objectType, instance); } } return descriptor; } } [SecuritySafeCritical] [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 var descriptor = base.GetTypeDescriptor(objectType, null); descriptors.Add(objectType, descriptor); try { // build a new descriptor from this, and replace the lookup descriptor = new HyperTypeDescriptor(descriptor); descriptors[objectType] = descriptor; return descriptor; } catch { // rollback and throw // (perhaps because the specific caller lacked permissions; // another caller may be successful) descriptors.Remove(objectType); throw; } } } }