发出 属性 的显式接口实现
Emit explicit interface implementation of a property
目标
所以我想做的是在运行时使用 TypeBuilder
class 创建一个类型。我希望运行时类型从中实现的接口如下所示。
public interface ITest
{
int TestProperty { get; }
}
应生成的类型应如下所示:
internal class Test : ITest
{
int ITest.TestProperty { get => 0; }
}
接口的显式实现并不是真正必要的,但这是我发现最多的资源。
现在进入实际代码
var assemblyName = new AssemblyName("AssemblyTest");
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
var module = assemblyBuilder.DefineDynamicModule(assemblyName.Name + ".dll");
var typeBuilder = module.DefineType("TestType", TypeAttributes.NotPublic | TypeAttributes.BeforeFieldInit | TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.Class, null, new[] { typeof(ITest) });
var prop = typeBuilder.DefineProperty("ITest.TestProperty", PropertyAttributes.HasDefault, typeof(int), null);
var propGet = typeBuilder.DefineMethod("ITest.get_TestProperty", MethodAttributes.Private | MethodAttributes.SpecialName | MethodAttributes.NewSlot | MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.Final);
var propertyGetIL = propGet.GetILGenerator();
propertyGetIL.Emit(OpCodes.Ldc_I4_0);
propertyGetIL.Emit(OpCodes.Ret);
prop.SetGetMethod(propGet);
typeBuilder.DefineMethodOverride(propGet, typeof(ITest).GetProperty("TestProperty").GetGetMethod());
var type = typeBuilder.CreateType();
作为代码的简短解释。
- 创建 DynamicAssembly/Module/Class
- 创建支持字段和 属性 本身
- 为 属性
创建 Get 方法的内容
- 将属性标记为接口的implementation
- 创建新类型
但是 CreateType
方法向我抛出以下内容:
Signature of the body and declaration in a method implementation do not match. Type: 'TestType'. Assembly: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.'
我真的不确定我将如何实施 属性 以及这是什么原因。
您在定义 get 方法时缺少 return 类型。您需要使用 different overload of DefineMethod
:
来指定它
var propGet = typeBuilder.DefineMethod("ITest.get_TestProperty",
MethodAttributes.Private | MethodAttributes.SpecialName | MethodAttributes.NewSlot |
MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.Final,
typeof(int), // <--- return type
Type.EmptyTypes // <-- parameter types (indexers)
);
目标
所以我想做的是在运行时使用 TypeBuilder
class 创建一个类型。我希望运行时类型从中实现的接口如下所示。
public interface ITest
{
int TestProperty { get; }
}
应生成的类型应如下所示:
internal class Test : ITest
{
int ITest.TestProperty { get => 0; }
}
接口的显式实现并不是真正必要的,但这是我发现最多的资源。
现在进入实际代码
var assemblyName = new AssemblyName("AssemblyTest");
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
var module = assemblyBuilder.DefineDynamicModule(assemblyName.Name + ".dll");
var typeBuilder = module.DefineType("TestType", TypeAttributes.NotPublic | TypeAttributes.BeforeFieldInit | TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.Class, null, new[] { typeof(ITest) });
var prop = typeBuilder.DefineProperty("ITest.TestProperty", PropertyAttributes.HasDefault, typeof(int), null);
var propGet = typeBuilder.DefineMethod("ITest.get_TestProperty", MethodAttributes.Private | MethodAttributes.SpecialName | MethodAttributes.NewSlot | MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.Final);
var propertyGetIL = propGet.GetILGenerator();
propertyGetIL.Emit(OpCodes.Ldc_I4_0);
propertyGetIL.Emit(OpCodes.Ret);
prop.SetGetMethod(propGet);
typeBuilder.DefineMethodOverride(propGet, typeof(ITest).GetProperty("TestProperty").GetGetMethod());
var type = typeBuilder.CreateType();
作为代码的简短解释。
- 创建 DynamicAssembly/Module/Class
- 创建支持字段和 属性 本身
- 为 属性 创建 Get 方法的内容
- 将属性标记为接口的implementation
- 创建新类型
但是 CreateType
方法向我抛出以下内容:
Signature of the body and declaration in a method implementation do not match. Type: 'TestType'. Assembly: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.'
我真的不确定我将如何实施 属性 以及这是什么原因。
您在定义 get 方法时缺少 return 类型。您需要使用 different overload of DefineMethod
:
var propGet = typeBuilder.DefineMethod("ITest.get_TestProperty",
MethodAttributes.Private | MethodAttributes.SpecialName | MethodAttributes.NewSlot |
MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.Final,
typeof(int), // <--- return type
Type.EmptyTypes // <-- parameter types (indexers)
);