misc optimization & refactoring

This commit is contained in:
Regalis
2015-09-29 18:03:38 +03:00
parent cc16bb3ad7
commit 45178e745b
30 changed files with 820 additions and 210 deletions
+108
View File
@@ -0,0 +1,108 @@
using System;
using System.ComponentModel;
namespace Hyper.ComponentModel {
public abstract class ChainingPropertyDescriptor : PropertyDescriptor {
private readonly PropertyDescriptor _root;
protected PropertyDescriptor Root { get { return _root; } }
protected ChainingPropertyDescriptor(PropertyDescriptor root)
: base(root) {
_root = root;
}
public override void AddValueChanged(object component, EventHandler handler) {
Root.AddValueChanged(component, handler);
}
public override AttributeCollection Attributes {
get {
return Root.Attributes;
}
}
public override bool CanResetValue(object component) {
return Root.CanResetValue(component);
}
public override string Category {
get {
return Root.Category;
}
}
public override Type ComponentType {
get { return Root.ComponentType; }
}
public override TypeConverter Converter {
get {
return Root.Converter;
}
}
public override string Description {
get {
return Root.Description;
}
}
public override bool DesignTimeOnly {
get {
return Root.DesignTimeOnly;
}
}
public override string DisplayName {
get {
return Root.DisplayName;
}
}
public override bool Equals(object obj) {
return Root.Equals(obj);
}
public override PropertyDescriptorCollection GetChildProperties(object instance, Attribute[] filter) {
return Root.GetChildProperties(instance, filter);
}
public override object GetEditor(Type editorBaseType) {
return Root.GetEditor(editorBaseType);
}
public override int GetHashCode() {
return Root.GetHashCode();
}
public override object GetValue(object component) {
return Root.GetValue(component);
}
public override bool IsBrowsable {
get {
return Root.IsBrowsable;
}
}
public override bool IsLocalizable {
get {
return Root.IsLocalizable;
}
}
public override bool IsReadOnly {
get { return Root.IsReadOnly; }
}
public override string Name {
get {
return Root.Name;
}
}
public override Type PropertyType {
get { return Root.PropertyType; }
}
public override void RemoveValueChanged(object component, EventHandler handler) {
Root.RemoveValueChanged(component, handler);
}
public override void ResetValue(object component) {
Root.ResetValue(component);
}
public override void SetValue(object component, object value) {
Root.SetValue(component, value);
}
public override bool ShouldSerializeValue(object component) {
return Root.ShouldSerializeValue(component);
}
public override bool SupportsChangeEvents {
get {
return Root.SupportsChangeEvents;
}
}
public override string ToString() {
return Root.ToString();
}
}
}
+50
View File
@@ -0,0 +1,50 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.50727</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{954502B1-7282-417D-9310-3332962A1CA1}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>HyperPropertyDescriptor</RootNamespace>
<AssemblyName>HyperPropertyDescriptor</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<UseVSHostingProcess>false</UseVSHostingProcess>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="ChainingPropertyDescriptor.cs" />
<Compile Include="HyperTypeDescriptionProvider.cs" />
<Compile Include="HyperTypeDescriptor.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
@@ -0,0 +1,5 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectView>ShowAllFiles</ProjectView>
</PropertyGroup>
</Project>
+74
View File
@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Security.Permissions;
/* Change history:
* 20 Apr 2007 Marc Gravell Rollback dictionary on error;
* Assert ReflectionPermission for main creation
* (thanks/credit to Josh Smith for feedback/hints)
*/
namespace Hyper.ComponentModel {
public sealed class HyperTypeDescriptionProvider : TypeDescriptionProvider {
public static void Add(Type type) {
TypeDescriptionProvider parent = TypeDescriptor.GetProvider(type);
TypeDescriptor.AddProvider(new HyperTypeDescriptionProvider(parent), type);
}
public HyperTypeDescriptionProvider() : this(typeof(object)) { }
public HyperTypeDescriptionProvider(Type type) : this(TypeDescriptor.GetProvider(type)) { }
public HyperTypeDescriptionProvider(TypeDescriptionProvider parent) : base(parent) { }
public static void Clear(Type type) {
lock (descriptors) {
descriptors.Remove(type);
}
}
public static void Clear() {
lock (descriptors) {
descriptors.Clear();
}
}
private static readonly Dictionary<Type, ICustomTypeDescriptor> descriptors = new Dictionary<Type, ICustomTypeDescriptor>();
public sealed override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance) {
ICustomTypeDescriptor descriptor;
lock (descriptors) {
if (!descriptors.TryGetValue(objectType, out descriptor)) {
try
{
descriptor = BuildDescriptor(objectType);
}
catch
{
return base.GetTypeDescriptor(objectType, instance);
}
}
return descriptor;
}
}
[ReflectionPermission( SecurityAction.Assert, Flags = ReflectionPermissionFlag.AllFlags)]
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);
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;
}
}
}
}
+218
View File
@@ -0,0 +1,218 @@
using System;
using System.ComponentModel;
using System.Reflection.Emit;
using System.Reflection;
using System.Threading;
using System.Collections.Generic;
using System.Diagnostics;
/* Change history:
* 20 Apr 2007 Marc Gravell Renamed
*/
namespace Hyper.ComponentModel {
sealed class HyperTypeDescriptor : CustomTypeDescriptor {
private readonly PropertyDescriptorCollection propertyCollections;
static readonly Dictionary<PropertyInfo, PropertyDescriptor> properties = new Dictionary<PropertyInfo, PropertyDescriptor>();
internal HyperTypeDescriptor(ICustomTypeDescriptor parent)
: base(parent) {
propertyCollections = WrapProperties(parent.GetProperties());
}
public sealed override PropertyDescriptorCollection GetProperties(Attribute[] attributes) {
return propertyCollections;
}
public sealed override PropertyDescriptorCollection GetProperties() {
return propertyCollections;
}
private static PropertyDescriptorCollection WrapProperties(PropertyDescriptorCollection oldProps) {
PropertyDescriptor[] newProps = new PropertyDescriptor[oldProps.Count];
int index = 0;
bool changed = false;
// HACK: how to identify reflection, given that the class is internal...
Type wrapMe = Assembly.GetAssembly(typeof(PropertyDescriptor)).GetType("System.ComponentModel.ReflectPropertyDescriptor");
foreach (PropertyDescriptor oldProp in oldProps) {
PropertyDescriptor pd = oldProp;
// if it looks like reflection, try to create a bespoke descriptor
if (ReferenceEquals(wrapMe, pd.GetType()) && TryCreatePropertyDescriptor(ref pd)) {
changed = true;
}
newProps[index++] = pd;
}
return changed ? new PropertyDescriptorCollection(newProps, true) : oldProps;
}
static readonly ModuleBuilder moduleBuilder;
static int counter;
static HyperTypeDescriptor() {
AssemblyName an = new AssemblyName("Hyper.ComponentModel.dynamic");
AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
moduleBuilder = ab.DefineDynamicModule("Hyper.ComponentModel.dynamic.dll");
}
private static bool TryCreatePropertyDescriptor(ref PropertyDescriptor descriptor) {
try {
PropertyInfo property = descriptor.ComponentType.GetProperty(descriptor.Name);
if (property == null) return false;
lock (properties) {
PropertyDescriptor foundBuiltAlready;
if (properties.TryGetValue(property, out foundBuiltAlready)) {
descriptor = foundBuiltAlready;
return true;
}
string name = "_c" + Interlocked.Increment(ref counter).ToString();
TypeBuilder tb = 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;
properties.Add(property, descriptor);
return true;
}
} catch {
return false;
}
}
}
}
+38
View File
@@ -0,0 +1,38 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
[assembly: AllowPartiallyTrustedCallers]
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("HyperTypeDescriptor")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("HyperTypeDescriptor")]
[assembly: AssemblyCopyright("Copyright © Marc Gravell 2007")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("f22bc56b-501e-438a-967e-8f0b48827869")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]