2016-12-29 1 views
1

J'écris un implementator d'interface pour les interfaces simples commeémettent correctement la propriété

interface IPoint 
{ 
    int X { get; } 
    int Y { get; } 
} 

Il fonctionne presque, mais lorsque je tente de mettre en œuvre toute propriété que je reçois une erreur

Signature du corps et la déclaration dans une implémentation de méthode ne correspondent pas

Je ne comprends pas pourquoi Emit pense que les propriétés ne correspondent pas.

exemple de code est ici:

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

Répondre

3

Essayez d'utiliser le 4-arg DefineMethod appeler les méthodes de get_ et set_ de sorte que vous pouvez définir le type de retour/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

Et il doit également être «virtuel». Merci, ça a réglé le problème. Defenitly doit dormir à 5h au lieu d'écrire du code émetteur :) –