Files
LuaCsForBarotraumaEP/Hyper.ComponentModel/HyperTypeDescriptionProvider.cs

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;
}
}
}
}