3

Je travaille actuellement sur la création d'un assemblage avec des propriétés virtuelles. Les exemples sur MSDN créent uniquement des propriétés normales. Comment puis-je créer une classe dans un assemblage qui a des propriétés virtuelles?Comment puis-je générer des propriétés virtuelles avec AssemblyBuilder en C# 4.0?

Je voudrais être en mesure de générer une classe comme ceci:

public class ClassA 
    { 
     public virtual int Id { get; set; } 
     public virtual string Name { get; set; } 
     public virtual string ClassName { get; set; } 
     public virtual ClassB Partner { get; set; } 
    } 

    public class ClassB 
    { 
     public virtual int Id { get; set; } 
     public virtual string Name { get; set; } 
    } 

La classe PropertyBuilder n'a pas PropertyAttributes.Virtual, donc je ne sais pas comment créer une propriété virtuelle. Si je crée moi-même cette classe dans Visual Studio, puis l'ouvre dans Reflector, les propriétés elles-mêmes sont virtuelles, c'est donc possible.

Comment cela peut-il être fait?

Répondre

3

Voici un exemple de création d'une classe à l'exécution qui contient une seule propriété entière Id qui est virtuel:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var aName = new AssemblyName("DynamicAssemblyExample"); 
     var ab = AppDomain.CurrentDomain.DefineDynamicAssembly(aName, AssemblyBuilderAccess.Run); 
     var mb = ab.DefineDynamicModule(aName.Name); 
     var tb = mb.DefineType("MyDynamicType", TypeAttributes.Public); 
     var fbId = tb.DefineField("_id", typeof(int), FieldAttributes.Private); 
     var pbId = tb.DefineProperty("Id", PropertyAttributes.HasDefault, typeof(int), null); 

     var getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual; 

     var mbIdGetAccessor = tb.DefineMethod("get_Id", getSetAttr, typeof(int), Type.EmptyTypes); 

     var numberGetIL = mbIdGetAccessor.GetILGenerator(); 
     numberGetIL.Emit(OpCodes.Ldarg_0); 
     numberGetIL.Emit(OpCodes.Ldfld, fbId); 
     numberGetIL.Emit(OpCodes.Ret); 

     var mbIdSetAccessor = tb.DefineMethod("set_Id", getSetAttr, null, new Type[] { typeof(int) }); 

     var numberSetIL = mbIdSetAccessor.GetILGenerator(); 
     numberSetIL.Emit(OpCodes.Ldarg_0); 
     numberSetIL.Emit(OpCodes.Ldarg_1); 
     numberSetIL.Emit(OpCodes.Stfld, fbId); 
     numberSetIL.Emit(OpCodes.Ret); 

     pbId.SetGetMethod(mbIdGetAccessor); 
     pbId.SetSetMethod(mbIdSetAccessor); 

     var t = tb.CreateType(); 
     var instance = Activator.CreateInstance(t); 
     Console.WriteLine(t.GetProperty("Id").GetGetMethod().IsVirtual); 
    } 
} 

La raison pour laquelle vous ne trouvez pas tout ce qui concerne virtual dans le PropertyBuilder est parce que les propriétés n » t avoir ce concept. Les méthodes peuvent être virtuelles. Ainsi, lorsque vous déclarez une propriété virtuelle , vous déclarez des méthodes getter et setter virtuelles. Jetez un oeil à l'énumération MethodAttributes.

+0

ab.Save() ne sauvegarde pas votre Assemblée créé (même avec le AssemblyBuilderAccess mis à RunAndSave) Pouvez-vous essayer d'enregistrer et charger l'ensemble de nouveau dans la mémoire? Je l'utilise dans mon propre logiciel pour contourner un bogue dans le framework .NET qui définit l'assembly comme un assembly d'exécution même après qu'il a été sauvegardé. Mais si j'utilise ceci sur votre code, il n'enregistre aucune propriété ou méthode. –

+0

Apparemment, j'ai fait quelque chose de mal avec votre code qui l'a empêché de fonctionner. Après avoir réessayé, ça fonctionne bien! –

+0

@ThijsCramer Si vous passez un nom de fichier à la méthode DefineDynamicModule, le fichier sera sauvegardé lorsque vous utiliserez ab.Save (FileName) plus tard. Je ne sais pas s'il s'agit d'un bug ou d'une fonctionnalité, car vous devez spécifier les noms de fichiers aux deux endroits et les deux peuvent être différents. L'assembly dll se référera au module dll –

Questions connexes