2016-12-29 3 views
1

Я пишу интерфейс реализатор для простых интерфейсов, какПравильно испускает свойство

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

И он также должен быть «виртуальным». Спасибо, он исправил проблему. Defenitly должен спать в 5 утра вместо написания испускающего кода :) –

Смежные вопросы