2016-12-29 62 views
1

我寫了簡單的接口界面implementator像正確發出財產

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; 
} 

回答

3

嘗試使用4 ARG DefineMethod呼籲的get_和set_方法,因此您可以將返回類型定義/ 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 }); 
+1

它也必須是「虛擬」的。謝謝,它解決了這個問題。毋庸置疑,必須在5AM睡覺,而不是寫作發射代碼:) –