The code below defines in Runtime a ClasseB
you inherit from your ClasseA
, where I added private fields to use in the properties instead of leaving it to the compiler.
The approach I used to ClasseB
seven the property Atributo
of ClasseA
added a new constructor to it (in Classeb), with a more.
Tested and working: https://dotnetfiddle.net/y6M72F
using System;
using System.Reflection;
using System.Reflection.Emit;
public class Program
{
public static void Main()
{
CriaClasseHerdandoOutra();
}
public static void CriaClasseHerdandoOutra() {
AssemblyName aName = new AssemblyName("DynamicAssemblyExample");
AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly(aName, AssemblyBuilderAccess.RunAndSave);
ModuleBuilder mb = ab.DefineDynamicModule(aName.Name, aName.Name + ".dll");
// define tipo "ClasseB" herdando de "ClasseA"
Type typeClasseA = Type.GetType("ClasseA");
TypeBuilder tb = mb.DefineType("ClasseB", TypeAttributes.Public, typeClasseA);
// obtém informação de atributos da "ClasseA" que serão setados
// no novo construtor da classe filha "ClasseB"
FieldInfo codigo = typeClasseA.GetField("_codigo", BindingFlags.NonPublic | BindingFlags.Instance);
FieldInfo atributo = typeClasseA.GetField("_atributo", BindingFlags.NonPublic | BindingFlags.Instance);
// cria no tipo "ClasseB" o construtor exigido por sua classe base
Type[] parameterTypes = {typeof(int)};
ConstructorBuilder ctor1 = tb.DefineConstructor(
MethodAttributes.Public,
CallingConventions.Standard,
parameterTypes);
// adiciona no construtor instruções para setar
// o atributo "Codigo" da classe base "ClasseA"
ILGenerator ctor1IL = ctor1.GetILGenerator();
ctor1IL.Emit(OpCodes.Ldarg_0);
ctor1IL.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
ctor1IL.Emit(OpCodes.Ldarg_0);
ctor1IL.Emit(OpCodes.Ldarg_1);
ctor1IL.Emit(OpCodes.Stfld, codigo);
ctor1IL.Emit(OpCodes.Ret);
// cria no tipo "ClasseB" um novo construtor,
// que recebe dois parâmetros
Type[] parameterTypes2 = { typeof(int), typeof(string)};
ConstructorBuilder ctor2 = tb.DefineConstructor(
MethodAttributes.Public,
CallingConventions.Standard,
parameterTypes2);
// adiciona no novo construtor instruções para setar
// os atributos "Codigo" e "Atributo" da classe base "ClasseA"
ILGenerator ctor2IL = ctor2.GetILGenerator();
ctor2IL.Emit(OpCodes.Ldarg_0);
ctor2IL.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
ctor2IL.Emit(OpCodes.Ldarg_0);
ctor2IL.Emit(OpCodes.Ldarg_1);
ctor2IL.Emit(OpCodes.Stfld, codigo);
ctor2IL.Emit(OpCodes.Ldarg_0);
ctor2IL.Emit(OpCodes.Ldarg_2);
ctor2IL.Emit(OpCodes.Stfld, atributo);
ctor2IL.Emit(OpCodes.Ret);
// cria o tipo que foi definido para "ClasseB"
Type ClasseBType = tb.CreateType();
// cria uma instância da "ClasseB", que acaba de ser definida
// em runtime (herdando de "ClasseA"), invocando seu novo construtor
// de dois parâmetros.
ClasseA objClasseB = (ClasseA)System.Activator.CreateInstance(ClasseBType, 1, "Rá!");
// invoca o método "Concatena" da classe base "ClasseA",
// o qual teve seu resultado afetado pela classe filha "ClasseB"
Console.WriteLine(objClasseB.Concatena());
}
}
public class ClasseA
{
protected string _atributo;
protected int _codigo;
protected string Atributo
{
get {return _atributo;}
set {_atributo = value; }
}
public int Codigo
{
get {return _codigo;}
set {_codigo = value; }
}
public ClasseA (int codigo)
{
Codigo = codigo;
}
public string Concatena()
{
return this.Atributo + " - " + this.Codigo;
}
}
Reference: documentation of the Assemblybuilder.
The key in this example are the classes TypeBuilder
, for the definition of a type in Runtime, and the ILGenerator
, to add instructions to the body of defined methods.
There are other ways to achieve similar results. Namely - Codedom and Roslyn, released in April this year (an example).
Considerations about my code
It is clear that this code is for educational purposes only and needs to be much more readable if used. It is also possible to generalize this code and abstract it to a nicer API that meets a specific need.
Besides, I imagine you’d wear Attributes do . Net’s to identify which properties to change instead of doing so based on the name.
A typical example of using this type of engineering (creating class inheritance at project runtime or build time) is in frameworks that do not want to force the user to inherit their classes but need to add resources to the user objects (ORMs, for example).
Why does the class need to be created dynamically? Is there a reason for this? There’s even a way to do it even though it’s not a class of truth that will be created (Expandoobject). But as far as I know can not use in inheritance. Nor would make sense. I think your problem is another. try to provide more information to indicate better the problem.
– Maniero
take a look at this link, maybe it’s what you want. http://msdn.microsoft.com/pt-br/library/ms404245(v=vs.110). aspx
– MeuChapeu
There’s even a way to create truth classes with Reflection or the new .Net Compiler Platform But I doubt that’s what you need, these are very complex resources to be used in very non-trivial situations like this problem seems to be. I think you’re just trying to create parameterized objects and not classes.
– Maniero
Because I use this base class to include mapping of entities in a context that is housed in a container, and the location that calls the method that "runs" that insertion of entities in context, checks whether the context class that will receive entities, no longer exists in an internal dictionary and does not allow it to occur more than once by the same class type. Soon, the idea arose of creating in Runtime instances of classes that inherit the methods of this base class, so that it is not necessary to 'codate' for each context a new class and use this generic class.
– TortugaGonca
There are two methods of generating Runtime code,
TypeBuilder
andCodeDOM
.TypeBuilder
is extremely difficult to use as it works at IL level. I agree with @bigown, I seriously doubt this is necessary to solve the problem.– dcastro
People walk fast on the trigger :D Yes, you can create real classes at runtime. Yes, you can create inheritance in Runtime. Yes, this can be very useful (many Orms work like this, inheriting our entities and adding resources to them). I just think that the AP has already tried something and in this case it could show what it has already achieved and the difficulties. The question already served at least to show that there is something that some did not dream.
– Caffé
Creating class instances is very different from creating classes. Instances inherit nothing, instances do not need. I understood the general context but I still have doubts whether the approach would be correct. It seems to me that you’re stuck with the concepts of OOP as if they solve anything simply. There are other ways to generalize the solution if this is so important. If it is not, there is no point in going to the trouble. See something about this at http://answall.com/a/15432/101
– Maniero
People, how can you close the question because it is not clear? The question is very clear! @bigown Has nothing to do with writing and compiling C#code. Net has a specific API for defining types in Runtime.
– Caffé
If you find the question clear and know how to resolve post your answer using the API. I think this problem does not need any of this but if I needed I would use the most practical way and now recommended by MS.
– Maniero