正确排放财产

时间:2016-12-29 01:47:16

标签: c# .net code-generation cil emit

我为

这样的简单接口编写了一个接口实现器
interface IPoint 
{
    int X { get; }
    int Y { get; }
}

它几乎可以工作,但是当我尝试实现任何属性时,我收到错误

  

方法实现中的正文和声明的签名不匹配

我不明白为什么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;
}

1 个答案:

答案 0 :(得分:3)

尝试对get_和set_方法使用4-arg DefineMethod调用,以便定义返回类型/ 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 });