Чтобы иметь возможность манипулировать свойствами во время выполнения, я пытаюсь создать универсальную оболочку, которая преобразует все публичные / непубличные, статические / свойства экземпляра в публичные свойства экземпляра, видимые в элементе управления PropertyGrid.
Приведенный ниже код отлично работает для общедоступных сеттеров и геттеров (как статических, так и для экземпляров), но не работает, скажем, с сеттерами, имеющими внутреннюю область действия.
Любая помощь приветствуется.
public static class PropertyWrapper<T> where T : class
{
public const BindingFlags DefaultBindingFlags = BindingFlags.Public
| BindingFlags.NonPublic
| BindingFlags.Static
| BindingFlags.Instance;
public static object Instance(T obj)
{
return Instance(obj, true, DefaultBindingFlags);
}
public static object Instance(T obj, bool readOnly)
{
return Instance(obj, readOnly, DefaultBindingFlags);
}
public static object Instance(T wrappedObject, bool readOnly, BindingFlags bindingFlags)
{
string commonName = "propertyWrapperModule.dll";
FieldAttributes fieldAttributes = FieldAttributes.Public;
string wrapperTypeName = wrappedObject.GetType().Name + "_WRAPPER";
AssemblyName assemblyName = new AssemblyName { Name = "commonName" };
AssemblyBuilder assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(commonName);
TypeBuilder typeBuilder = moduleBuilder.DefineType(wrapperTypeName, TypeAttributes.Public | TypeAttributes.Class);
var objProperties = wrappedObject.GetType().GetProperties(bindingFlags);
foreach (var objProperty in objProperties)
{
// Field
FieldBuilder fieldBuilder = typeBuilder.DefineField(objProperty.Name, objProperty.PropertyType, fieldAttributes);
// Property
PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(objProperty.Name,
PropertyAttributes.None,
objProperty.PropertyType,
new Type[] { objProperty.PropertyType });
// Define Getter
if (objProperty.CanRead)
{
MethodInfo objGetterMethodInfo = objProperty.GetGetMethod(true);
if (objGetterMethodInfo != null)
{
MethodBuilder getterMethodBuilder = DefineGetter(objGetterMethodInfo, typeBuilder, fieldBuilder);
propertyBuilder.SetGetMethod(getterMethodBuilder);
}
}
// Define Setter
if (objProperty.CanWrite)
{
MethodInfo objSetterMethodInfo = objProperty.GetSetMethod(true);
if (objSetterMethodInfo != null)
{
MethodBuilder methodBuilderSetter = DefineSetter(objSetterMethodInfo, typeBuilder, fieldBuilder); // , objectType);
propertyBuilder.SetSetMethod(methodBuilderSetter);
}
}
}
Type wrapperType = typeBuilder.CreateType();
var wrapperObject = Activator.CreateInstance(wrapperType);
// Test
var wrapperProperties = wrapperType.GetProperties();
// Save assembly
assemblyBuilder.Save(commonName);
return wrapperObject;
} // public object CreateNewObject(T obj)
private static MethodBuilder DefineGetter(MethodInfo getterMethodInfo, TypeBuilder typeBuilder, FieldBuilder fieldBuilder) // Type objectType)
{
MethodAttributes attributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName; // | MethodAttributes.Virtual;
MethodBuilder getterMethodBuilder = typeBuilder.DefineMethod
(
getterMethodInfo.Name,
attributes,
getterMethodInfo.ReturnType,
Type.EmptyTypes
);
// Generate IL
ILGenerator ilGenerator = getterMethodBuilder.GetILGenerator();
ilGenerator.DeclareLocal(fieldBuilder.FieldType);
ilGenerator.Emit(OpCodes.Nop);
if (!getterMethodInfo.IsStatic)
{
ilGenerator.Emit(OpCodes.Ldarg_0);
}
ilGenerator.EmitCall(OpCodes.Callvirt, getterMethodInfo, null);
ilGenerator.Emit(OpCodes.Stloc_0);
// http://stackoverflow.com/questions/6766839/using-br-s-opcode-to-point-to-next-instruction-using-reflection-emit-label
Label targetInstruction = ilGenerator.DefineLabel();
ilGenerator.Emit(OpCodes.Br_S, targetInstruction);
ilGenerator.MarkLabel(targetInstruction);
ilGenerator.Emit(OpCodes.Ldloc_0);
ilGenerator.Emit(OpCodes.Ret);
return getterMethodBuilder;
}
private static MethodBuilder DefineSetter(MethodInfo setterMethodInfo, TypeBuilder typeBuilder, FieldBuilder fieldBuilder)
{
MethodAttributes attributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName;
MethodBuilder setterMethodBuilder = typeBuilder.DefineMethod
(
setterMethodInfo.Name,
attributes,
null,
new Type[] { fieldBuilder.FieldType }
);
// Generate IL
ILGenerator ilGenerator = setterMethodBuilder.GetILGenerator();
ilGenerator.Emit(OpCodes.Nop);
if (!setterMethodInfo.IsStatic)
{
ilGenerator.Emit(OpCodes.Ldarg_0);
}
ilGenerator.Emit(OpCodes.Ldarg_1);
ilGenerator.EmitCall(OpCodes.Callvirt, setterMethodInfo, null);
ilGenerator.Emit(OpCodes.Ret);
return setterMethodBuilder;
}
}