正确发射 属性
Properly emit property
我正在为像
这样的简单接口编写一个接口实现器
interface IPoint
{
int X { get; }
int Y { get; }
}
它几乎可以工作,但是当我尝试实施任何 属性 时,我得到一个错误
Signature of the body and declaration in a method implementation do not match
不明白为什么Emit
认为属性不匹配
这是代码示例:
private static class InterfaceImplementator<T> where T: class
{
[SuppressMessage("ReSharper", "StaticMemberInGenericType")]
public static Type Value { get; }
static InterfaceImplementator()
{
var interfaceType = typeof(T);
if (!interfaceType.IsInterface)
{
throw new ArgumentException($"{interfaceType.FullName} should be an interface!");
}
var interfaceProps = interfaceType.GetProperties();
if (interfaceType.GetMethods().Except(interfaceProps.Select(x => x.GetMethod).Concat(interfaceProps.Select(x => x.SetMethod))).Any())
{
throw new ArgumentException($"{interfaceType.FullName} must have properties only!");
}
var tb = Builder.DefineType($"<{interfaceType.Name}>__Implementation", TypeAttributes.Class | TypeAttributes.Sealed);
foreach (var interfaceProp in interfaceProps)
{
var prop = tb.EmitAutoProperty(interfaceProp.Name, interfaceProp.PropertyType);
if (interfaceProp.CanRead)
{
tb.DefineMethodOverride(prop.GetMethod, interfaceProp.GetMethod);
}
if (interfaceProp.CanWrite)
{
tb.DefineMethodOverride(prop.SetMethod, interfaceProp.SetMethod);
}
}
tb.AddInterfaceImplementation(interfaceType);
Value = tb.CreateType();
}
}
其中 EmitProperty
:
public static PropertyInfo EmitAutoProperty(this TypeBuilder tb, string propertyName, Type propertyType)
{
var backingField = tb.DefineField($"<{propertyName}>k__BackingField", propertyType, FieldAttributes.Private);
var propertyBuilder = tb.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
var getMethod = tb.DefineMethod("get_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig);
var getGenerator = getMethod.GetILGenerator();
getGenerator.Emit(OpCodes.Ldarg_0);
getGenerator.Emit(OpCodes.Ldfld, backingField);
getGenerator.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(getMethod);
var setMethod = tb.DefineMethod("set_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig);
var setGenerator = setMethod.GetILGenerator();
setGenerator.Emit(OpCodes.Ldarg_0);
setGenerator.Emit(OpCodes.Ldarg_1);
setGenerator.Emit(OpCodes.Stfld, backingField);
setGenerator.Emit(OpCodes.Ret);
propertyBuilder.SetSetMethod(setMethod);
return propertyBuilder;
}
尝试对 get_ 和 set_ 方法使用 4-arg DefineMethod 调用,这样您就可以定义 return 类型/arg:
var getMethod = tb.DefineMethod("get_" + propertyName,
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
propertyType,
Type.EmptyTypes);
var setMethod = tb.DefineMethod("set_" + propertyName,
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
null,
new [] { propertyType });
我正在为像
这样的简单接口编写一个接口实现器interface IPoint
{
int X { get; }
int Y { get; }
}
它几乎可以工作,但是当我尝试实施任何 属性 时,我得到一个错误
Signature of the body and declaration in a method implementation do not match
不明白为什么Emit
认为属性不匹配
这是代码示例:
private static class InterfaceImplementator<T> where T: class
{
[SuppressMessage("ReSharper", "StaticMemberInGenericType")]
public static Type Value { get; }
static InterfaceImplementator()
{
var interfaceType = typeof(T);
if (!interfaceType.IsInterface)
{
throw new ArgumentException($"{interfaceType.FullName} should be an interface!");
}
var interfaceProps = interfaceType.GetProperties();
if (interfaceType.GetMethods().Except(interfaceProps.Select(x => x.GetMethod).Concat(interfaceProps.Select(x => x.SetMethod))).Any())
{
throw new ArgumentException($"{interfaceType.FullName} must have properties only!");
}
var tb = Builder.DefineType($"<{interfaceType.Name}>__Implementation", TypeAttributes.Class | TypeAttributes.Sealed);
foreach (var interfaceProp in interfaceProps)
{
var prop = tb.EmitAutoProperty(interfaceProp.Name, interfaceProp.PropertyType);
if (interfaceProp.CanRead)
{
tb.DefineMethodOverride(prop.GetMethod, interfaceProp.GetMethod);
}
if (interfaceProp.CanWrite)
{
tb.DefineMethodOverride(prop.SetMethod, interfaceProp.SetMethod);
}
}
tb.AddInterfaceImplementation(interfaceType);
Value = tb.CreateType();
}
}
其中 EmitProperty
:
public static PropertyInfo EmitAutoProperty(this TypeBuilder tb, string propertyName, Type propertyType)
{
var backingField = tb.DefineField($"<{propertyName}>k__BackingField", propertyType, FieldAttributes.Private);
var propertyBuilder = tb.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
var getMethod = tb.DefineMethod("get_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig);
var getGenerator = getMethod.GetILGenerator();
getGenerator.Emit(OpCodes.Ldarg_0);
getGenerator.Emit(OpCodes.Ldfld, backingField);
getGenerator.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(getMethod);
var setMethod = tb.DefineMethod("set_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig);
var setGenerator = setMethod.GetILGenerator();
setGenerator.Emit(OpCodes.Ldarg_0);
setGenerator.Emit(OpCodes.Ldarg_1);
setGenerator.Emit(OpCodes.Stfld, backingField);
setGenerator.Emit(OpCodes.Ret);
propertyBuilder.SetSetMethod(setMethod);
return propertyBuilder;
}
尝试对 get_ 和 set_ 方法使用 4-arg DefineMethod 调用,这样您就可以定义 return 类型/arg:
var getMethod = tb.DefineMethod("get_" + propertyName,
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
propertyType,
Type.EmptyTypes);
var setMethod = tb.DefineMethod("set_" + propertyName,
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
null,
new [] { propertyType });