126 lines
4.4 KiB
C#
126 lines
4.4 KiB
C#
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<Type, ICustomTypeDescriptor> descriptors = new Dictionary<Type, ICustomTypeDescriptor>();
|
|
private static readonly Dictionary<Type, TypeDescriptionProvider> providers = new Dictionary<Type, TypeDescriptionProvider>();
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
} |