我想一个类绑定在一起,A和接口B,并创建一个类型C,从而C实现接口B。也:
C有一个构造函数,该构造函数将类型的对象A作为构造函数,我们称之为iA对B(假设在地图上的所有属性具有相同的类型),那么它使用从属性值i来代替。例如:
class A { public string Name { get; set; } }
interface B { string Name { get; set; } }
class C : B {
private readonly A _i;
public C(A i) {
_i = i;
}
public string Name
{
get => _i.Name;
set => _i.Name = value;
}
}
Run Code Online (Sandbox Code Playgroud)
这就是我所做的(通常,我指的B是源代码A):
/// <summary>
/// Creates a new type dynamically
/// </summary>
public class CustomTypeGenerator<TSource, TCommon>
{
private readonly TypeBuilder _tb;
private readonly FieldBuilder _entityFieldBldr;
private readonly Type _srcType;
/// <summary>
/// Initialize custom type builder
/// </summary>
public CustomTypeGenerator(IEnumerable<(string CommonPrpName, Type Type, string SourcePrpName)> members)
{
var cmType = typeof(TCommon);
_srcType = typeof(TSource);
if (!cmType.IsInterface)
{
throw new Exception("Type has to be an interface");
}
const string assemblyName = "DynamicAseembly123";
const string typeSignature = "DynamicType123";
var assemblyBuilder =
AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(assemblyName), AssemblyBuilderAccess.Run);
var moduleBuilder = assemblyBuilder.DefineDynamicModule("Module123");
_tb = moduleBuilder.DefineType(typeSignature,
TypeAttributes.Public |
TypeAttributes.Class |
TypeAttributes.AutoClass |
TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout);
_tb.AddInterfaceImplementation(cmType);
_entityFieldBldr = EmitSourceField();
_tb.DefineDefaultConstructor(
MethodAttributes.Public |
MethodAttributes.SpecialName |
MethodAttributes.RTSpecialName);
var constructorBuilder = _tb.DefineConstructor(MethodAttributes.Public,
CallingConventions.Standard,
new[] {_srcType});
constructorBuilder.DefineParameter(0, ParameterAttributes.None, "entity");
var constructorIl = constructorBuilder.GetILGenerator();
constructorIl.Emit(OpCodes.Ldarg_0);
constructorIl.Emit(OpCodes.Ldarg_1);
constructorIl.Emit(OpCodes.Stfld, _entityFieldBldr);
constructorIl.Emit(OpCodes.Ret);
foreach (var (commonPrpName, type, sourcePrpName) in members)
{
EmitProperty(commonPrpName, type, sourcePrpName);
}
EmittedType = _tb.CreateType();
}
public Type EmittedType { get; }
private FieldBuilder EmitSourceField()
{
var entityBldr = _tb.DefineField("_" + "entity", _srcType, FieldAttributes.Private);
return entityBldr;
}
private void EmitProperty(string cPn, Type cmPt, string sPn)
{
var srcProp = _srcType.GetProperty(sPn, BindingFlags.Public | BindingFlags.Instance);
var propertyBldr = _tb.DefineProperty(cPn, PropertyAttributes.HasDefault, cmPt, null);
var getterMethodInfo = srcProp.GetMethod ?? throw new Exception("Missing getter!");
var getPropMthdBldr = _tb.DefineMethod($"get_{cPn}",
MethodAttributes.Public |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig,
cmPt, Type.EmptyTypes);
var getIl = getPropMthdBldr.GetILGenerator();
var getProperty = getIl.DefineLabel();
var exitGet = getIl.DefineLabel();
getIl.MarkLabel(getProperty);
getIl.Emit(OpCodes.Ldarg_0);
getIl.Emit(OpCodes.Ldfld, _entityFieldBldr);
getIl.Emit(OpCodes.Call, getterMethodInfo);
getIl.Emit(OpCodes.Dup);
getIl.MarkLabel(exitGet);
getIl.Emit(OpCodes.Ret);
var setterMethodInfo = srcProp.SetMethod ?? throw new Exception("Missing setter!");
var setPropMthdBldr = _tb.DefineMethod($"set_{cPn}",
MethodAttributes.Public |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig,
null, new[] {cmPt});
var setIl = setPropMthdBldr.GetILGenerator();
var modifyProperty = setIl.DefineLabel();
var exitSet = setIl.DefineLabel();
setIl.MarkLabel(modifyProperty);
setIl.Emit(OpCodes.Ldarg_0);
getIl.Emit(OpCodes.Ldfld, _entityFieldBldr);
setIl.Emit(OpCodes.Ldarg_1);
getIl.Emit(OpCodes.Call, setterMethodInfo);
setIl.Emit(OpCodes.Nop);
setIl.MarkLabel(exitSet);
setIl.Emit(OpCodes.Ret);
propertyBldr.SetGetMethod(getPropMthdBldr);
propertyBldr.SetSetMethod(setPropMthdBldr);
}
}
Run Code Online (Sandbox Code Playgroud)
我得到的例外:
程序集“ DynamicAseembly123”中版本“ DynamicType123”中的类型“ DynamicType123”中的方法“ get_Name”,版本= 0.0.0.0,Culture = neutral,PublicKeyToken = null,没有实现。
感谢您的帮助或提示。
更新:我曾经ILSpy在虚拟示例代码上监视生成的IL:
.class private auto ansi beforefieldinit ConsoleApp1.C
extends [System.Runtime]System.Object
implements ConsoleApp1.B
{
// Fields
.field private initonly class ConsoleApp1.A _i
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor (
class ConsoleApp1.A i
) cil managed
{
// Method begins at RVA 0x206a
// Code size 16 (0x10)
.maxstack 8
// (no C# code)
IL_0000: ldarg.0
IL_0001: call instance void [System.Runtime]System.Object::.ctor()
IL_0006: nop
IL_0007: nop
// _i = i;
IL_0008: ldarg.0
IL_0009: ldarg.1
IL_000a: stfld class ConsoleApp1.A ConsoleApp1.C::_i
// (no C# code)
IL_000f: ret
} // end of method C::.ctor
.method public final hidebysig specialname newslot virtual
instance string get_Name () cil managed
{
// Method begins at RVA 0x207b
// Code size 12 (0xc)
.maxstack 8
// return _i.Name;
IL_0000: ldarg.0
IL_0001: ldfld class ConsoleApp1.A ConsoleApp1.C::_i
IL_0006: callvirt instance string ConsoleApp1.A::get_Name()
// (no C# code)
IL_000b: ret
} // end of method C::get_Name
.method public final hidebysig specialname newslot virtual
instance void set_Name (
string 'value'
) cil managed
{
// Method begins at RVA 0x2088
// Code size 14 (0xe)
.maxstack 8
// _i.Name = value;
IL_0000: ldarg.0
IL_0001: ldfld class ConsoleApp1.A ConsoleApp1.C::_i
IL_0006: ldarg.1
IL_0007: callvirt instance void ConsoleApp1.A::set_Name(string)
// (no C# code)
IL_000c: nop
IL_000d: ret
} // end of method C::set_Name
// Properties
.property instance string Name()
{
.get instance string ConsoleApp1.C::get_Name()
.set instance void ConsoleApp1.C::set_Name(string)
}
} // end of class ConsoleApp1.C
Run Code Online (Sandbox Code Playgroud)
我使用了提示ILSpy来获取一些提示,这是我更新的C#代码:
/// <summary>
/// Creates a new type dynamically
/// </summary>
public class CustomTypeGenerator<TSource, TCommon>
{
private readonly TypeBuilder _tb;
private readonly FieldBuilder _entityFieldBldr;
private readonly Type _srcType;
/// <summary>
/// Initialize custom type builder
/// </summary>
public CustomTypeGenerator(Dictionary<string, (Type Type, string SourcePrpName)> members)
{
var objType = typeof(object);
var cmType = typeof(TCommon);
_srcType = typeof(TSource);
if (!cmType.IsInterface)
{
throw new Exception("Type has to be an interface");
}
const string assemblyName = "DynamicAssembly123";
const string typeSignature = "DynamicType123";
var assemblyBuilder =
AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(assemblyName), AssemblyBuilderAccess.Run);
var moduleBuilder = assemblyBuilder.DefineDynamicModule("Module123");
_tb = moduleBuilder.DefineType(typeSignature,
TypeAttributes.Public |
TypeAttributes.Serializable |
TypeAttributes.Class |
TypeAttributes.Sealed |
TypeAttributes.AutoLayout, objType);
_tb.AddInterfaceImplementation(cmType);
_entityFieldBldr = EmitSourceField();
_tb.DefineDefaultConstructor(
MethodAttributes.Public |
MethodAttributes.SpecialName |
MethodAttributes.RTSpecialName);
var constructorBuilder = _tb.DefineConstructor(MethodAttributes.Public,
CallingConventions.Standard,
new[] {_srcType});
constructorBuilder.DefineParameter(0, ParameterAttributes.None, "entity");
var constructorIl = constructorBuilder.GetILGenerator();
constructorIl.Emit(OpCodes.Ldarg_0);
constructorIl.Emit(OpCodes.Ldarg_1);
constructorIl.Emit(OpCodes.Stfld, _entityFieldBldr);
constructorIl.Emit(OpCodes.Ret);
foreach (var (commonPrpName, (type, sourcePrpName)) in members)
{
EmitProperty(commonPrpName, type, sourcePrpName);
}
EmittedType = _tb.CreateType();
}
public Type EmittedType { get; }
private FieldBuilder EmitSourceField()
{
var entityBldr = _tb.DefineField("_" + "entity", _srcType,
FieldAttributes.Private |
FieldAttributes.InitOnly);
return entityBldr;
}
private void EmitProperty(string cPn, Type cmPt, string sPn)
{
var srcProp = _srcType.GetProperty(sPn, BindingFlags.Public | BindingFlags.Instance);
var getterMethodInfo = srcProp.GetMethod ?? throw new Exception("Missing getter!");
var getPropMthdBldr = _tb.DefineMethod($"get_{cPn}",
MethodAttributes.Public |
MethodAttributes.Virtual |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig,
cmPt, Type.EmptyTypes);
var getIl = getPropMthdBldr.GetILGenerator();
var getPropertyLbl = getIl.DefineLabel();
var exitGetLbl = getIl.DefineLabel();
getIl.MarkLabel(getPropertyLbl);
getIl.Emit(OpCodes.Ldarg_0);
getIl.Emit(OpCodes.Ldfld, _entityFieldBldr);
getIl.Emit(OpCodes.Callvirt, getterMethodInfo);
getIl.MarkLabel(exitGetLbl);
getIl.Emit(OpCodes.Ret);
var setterMethodInfo = srcProp.SetMethod ?? throw new Exception("Missing setter!");
var setPropMthdBldr = _tb.DefineMethod($"set_{cPn}",
MethodAttributes.Public |
MethodAttributes.Virtual |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig,
null, new[] {cmPt});
var setIl = setPropMthdBldr.GetILGenerator();
var modifyPropertyLbl = setIl.DefineLabel();
var exitSetLbl = setIl.DefineLabel();
setIl.MarkLabel(modifyPropertyLbl);
setIl.Emit(OpCodes.Ldarg_0);
getIl.Emit(OpCodes.Ldfld, _entityFieldBldr);
setIl.Emit(OpCodes.Ldarg_1);
getIl.Emit(OpCodes.Callvirt, setterMethodInfo);
setIl.Emit(OpCodes.Nop);
setIl.MarkLabel(exitSetLbl);
setIl.Emit(OpCodes.Ret);
var propertyBldr = _tb.DefineProperty(cPn, PropertyAttributes.None, cmPt, null);
propertyBldr.SetGetMethod(getPropMthdBldr);
propertyBldr.SetSetMethod(setPropMthdBldr);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
133 次 |
| 最近记录: |