2017-10-15 40 views
0

Recherche d'une résolution sur la façon d'affecter des propriétés avec des champs de sauvegarde que j'ai créés dynamiquement à la température ambiante dans un constructeur d'instance. Les signatures correspondent aux attributs générés par le compilateur en tant que propriétés automatiques. Essentiellement, ils seraient équivalents au code ci-dessous.Affectation de champs dans le constructeur via Reflection Emit

En utilisant Core .NET 2.0

Question: Comment attribuer les champs d'accompagnement au sein du constructeur en utilisant Emit?

Par exemple:

public class MyClass { 
    public MyClass(int f1, string f2) { 
    _field1 = f1; 
    _field2 = f2; 
    } 

    private readonly int _field1; 
    private readonly string _field2; 

    public int Field1 { get; } 
    public string Field2 { get; } 
} 

private static void CreateConstructor(TypeBuilder typeBuilder, IReadOnlyList<dynamic> backingFields) { 
    var constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard, new[] {typeof(KeyValuePair<string, string>), typeof(Dictionary<string, Type>)}); 
    var ctorIL = constructorBuilder.GetILGenerator(); 

    // Load the current instance ref in arg 0, along 
    // with the value of parameter "x" stored in arg X, into stfld. 

    for (var x = 0; x < backingFields.Count; x++) { 
    ctorIL.Emit(OpCodes.Ldarg_0); 
    ctorIL.Emit(OpCodes.Ldarg_S, x+1); 
    ctorIL.Emit(OpCodes.Stfld, backingFields[x]); 
    } 

    ctorIL.Emit(OpCodes.Ret); 
} 

public .cctor(KeyValuePair<string, string> kvp, Dictionary<string, Type> collection) { 
    _Name = kvp.Key; 
    _JSON = kvp.Value; 
    _PropertyInfo = collection; 
    } 

itérer sur des méthodes définies dans l'interface et créer une nouvelle propriétés & accesseurs w/private setters dans le nouveau type .

public interface IComplexType { 
    string Name { get; set; } 
    string JSON { get; set; } 
    object PropertyInfo { get; set; } 
    } 
+0

code DOM est significativement plus facile que Refection Emit – MickyD

+1

Le code que vous avez posté semble attribuer les arguments du constructeur aux champs de support. Est-ce que ça ne marche pas? –

+0

Quelque chose ne fonctionne pas correctement. Il compile et retourne le type. Capable de créer une instance .. lors de l'inspection, il me manque des champs/propriétés. Par exemple, je suis supposé avoir une classe avec Interface contenant 3 champs. Le JSON ajoutera des champs/propriétés/méthodes supplémentaires à la classe qui fonctionne, mais j'essaye de faire en sorte que les membres ne se lisent que dans l'interface. public interface IComplexType { chaîne Nom {get; ensemble; } chaîne JSON {get; ensemble; } [Bindable (true)] [TypeConverter (typeof (StringConverter))] object PropertyInfo {get; ensemble; } } – Latency

Répondre

1

Résolu!

Nécessaire pour modifier les arguments constructeurs afin qu'ils correspondent au nombre d'itérations car il était plus difficile de définir Ldarg_1 en tant que KeyValuePair et d'affecter sa valeur Key & respectivement.

En éliminant le KVP et en fournissant un paramètre supplémentaire du constructeur est défini comme suit:

var constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard, new[] {typeof(string), typeof(string), typeof(Dictionary<string, Type>)}); 
    var ctorIl = constructorBuilder.GetILGenerator(); 

    for (var x = 0; x < backingFields.Count; x++) { 
    ctorIl.Emit(OpCodes.Ldarg_0); 
    ctorIl.Emit(OpCodes.Ldarg_S, x + 1); 
    ctorIl.Emit(OpCodes.Stfld, backingFields[x]); 
    } 

    ctorIl.Emit(OpCodes.Ret); 

Pour appeler, je viens extraire le contenu du KVP ici:

return (T) Activator.CreateInstance(TypeCollection[type], kvp.Key, kvp.Value, collection);