L'idea di base è di costruirsi a RunTime delle Classi banalmente Entity con Get e Set, di contro tutto quello che ho trovato su WEB, mi ha sempre lasciato perplesso, tremendamente perplesso. Quintali e quintali di codice poco comprensibili.
Rimango dell'idea ( sfide a parte ) che il codice debba comunque essere leggibile e a tal proposito chi deve leggere deve comprendere ciò che sta leggendo.
Ciò detto .. ecco il quanto.
Questa semplice ma pur efficace console application serve a mostrare come generare una classe Entity partendo da una definizione (che potrebbe essere frutto di un XML).
Framework: 4.0
Reference:Microsoft.CSharp
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Microsoft.CSharp;
using System.CodeDom;
using System.CodeDom.Compiler;
namespace cDynamicType
{
public class entity
{
public string className { get; set; }
public string classNamespace { get; set; }
public List<entityPropertyType> classProperties = new List<entityPropertyType>();
}
public class entityPropertyType
{
public string propertyName { get; set; }
public string propertyType { get; set; }
public bool readOnly { get; set; }
}
class Program
{
static void Main(string[] args)
{
entity e = new entity();
e.className = "entityTest";
e.classNamespace = "Test.Entities";
e.classProperties.Add(new entityPropertyType() {
propertyName = "ID",
propertyType = "Int32",
readOnly = false });
e.classProperties.Add(new entityPropertyType() {
propertyName = "Name",
propertyType = "System.string",
readOnly = false });
e.classProperties.Add(new entityPropertyType() {
propertyName = "Description",
propertyType = "System.string",
readOnly = false });
CSharpCodeProvider cProvider = new CSharpCodeProvider();
ICodeCompiler cCompiler = cProvider.CreateCompiler();
CompilerParameters parameters = new CompilerParameters();
parameters.ReferencedAssemblies.Add("System.dll");
CodeCompileUnit unit = new CodeCompileUnit();
unit.ReferencedAssemblies.Add("System.dll");
CodeNamespace customEntityRoot = new CodeNamespace(e.classNamespace);
unit.Namespaces.Add(customEntityRoot);
customEntityRoot.Imports.Add(new CodeNamespaceImport("System"));
CodeTypeDeclaration Entity = new CodeTypeDeclaration(e.className);
customEntityRoot.Types.Add(Entity);
CodeConstructor EntityClassConstructor = new CodeConstructor();
EntityClassConstructor.Attributes = MemberAttributes.Public;
for (int i = 0; i < e.classProperties.Count; i++)
{
CodeMemberProperty cp = new CodeMemberProperty();
cp.Name = e.classProperties[i].propertyName;
cp.Type = new CodeTypeReference(e.classProperties[i].propertyType);
cp.HasGet = true;
cp.HasSet = true;
Entity.Members.Add(cp);
}
ICodeGenerator cGenerator = cProvider.CreateGenerator();
StringBuilder generatedCode = new StringBuilder();
StringWriter cWriter = new StringWriter(generatedCode);
CodeGeneratorOptions options = new CodeGeneratorOptions();
options.BracingStyle = "C";
cGenerator.GenerateCodeFromCompileUnit(unit, cWriter, options);
CompilerResults results = cProvider.CompileAssemblyFromSource(
parameters,
generatedCode.ToString()
);
Console.WriteLine(generatedCode.ToString());
Console.WriteLine(results.PathToAssembly);
Console.ReadKey();
cProvider = null;
cCompiler = null;
parameters = null;
cGenerator = null;
cWriter = null;
}
}
}
Le prime due classi mi servono per rappresentare l'entità di cui fare il render.
di cui entity si porta dietro poco nulla se non il nome della classe, il namespace e le propretà. La seconda sono le proprietà.
Il processo è semplice:
crea il provider,
crea il compiler,
crea il namespace,
aggiunge le referenze,
aggiunge le using,
crea le proprietà,
compila.
Cosa Manca, certo questo codice come sempre o quasi pecca in molto perchè non è del tutto completo tuttavi può essere un buon spunto su cui ragionare.
Nessun commento:
Posta un commento