2012-02-23 15 views
6

¿Puedo construir una clase como se muestra a continuación de forma dinámica mediante la reflexión? No hay métodos, solo variables públicas, algunos tienen atributos personalizados.Usar la reflexión para crear una clase (para crear una clase dinámica FileHelper)

Se requiere el método .Emit (por lo que he visto, "Emitir" parece un poco desafiante).

Estoy usando software desde www.FileHelpers.net, y requiere una clase. Todas mis definiciones de archivo están en una tabla de base de datos, y me gustaría que todo sea más dinámico (es decir, no cambia el código cuando aparece una nueva columna en el archivo).

[FileHelpers.DelimitedRecord(",")] 
public class FileRow 
{ 
    [FileHelpers.FieldQuoted('"', QuoteMode.OptionalForBoth)] 
    public string Borrower_First_Name; 
    [FileHelpers.FieldQuoted('"', QuoteMode.OptionalForBoth)] 
    public string Borrower_Last_Name; 
    public string Borrower_Email; 
} 

Actualización 1: Sobre la base de la respuesta de Vlad a continuación que necesitaba para hacer referencia a la DLL, aquí está cómo lo hice:

// need to reference the FileHelpers.dll from our own .exe directory 
    string diskFilenameFileHelpersDLL = 
     System.IO.Path.GetDirectoryName(
      System.Reflection.Assembly.GetExecutingAssembly().Location) + 
      @"\FileHelpers.dll"; 

Actualización 2: También, después de hacer lo que sugirió Vlad, así es como me llamo FileHelper y recorra los resultados. Probablemente transferiré los datos a una lista.

Assembly assembly = compiledResult.CompiledAssembly; 

    // Simple Data Test 
    lineContents = "John,Doe,[email protected]"; 
    FileHelperEngine engine = new FileHelperEngine(assembly.GetType("FileRow")); 
    // FileRow[] FileRowArray = (FileRow[])engine.ReadString(lineContents); 
    Object[] FileRowArray = engine.ReadString(lineContents); 
    Object myObject = FileRowArray[0]; // only 1 row of data in this example 

    // Get the type handle of a specified class. 
    Type myType = assembly.GetType("FileRow"); 
    // Get the fields of the specified class. 
    FieldInfo[] myField = myType.GetFields(); 

    Console.WriteLine("\nDisplaying fields values:\n"); 
    for (int i = 0; i < myField.Length; i++) 
    { 
     Object objTest = myField.GetValue(i); 

     string tempName = myField[i].Name; 
     Object objTempValue = myField[i].GetValue(myObject); 
     string tempValue = System.Convert.ToString(objTempValue); 

     Console.WriteLine("The value of {0} is: {1}", 
          tempName, tempValue); 

    } 
+2

Tome un vistazo a [hola, mundo ... Reflection.Emit estilo!] (Http://blogs.msdn.com/b/joelpob/archive/2004/01/21/61411.aspx) –

+0

¿Emite específicamente crear un .DLL o .EXE? Solo necesito una clase en la memoria, nada guardado en el disco. – NealWalters

+0

Estaba diciendo que NO necesito guardar en el disco. – NealWalters

Respuesta

2

Si ha almacenado el código en la base de datos como una cadena lo que puede hacer algo como esto para crear un montaje:

La razón por la que comento a cabo atributos porque yo no' t tienen espacio de nombres para ellos. Supongo que tienes espacio de nombre y deberás agregarlo a tu código para compilarlo.

El código funciona en LINQPad, por lo que solo puede copiar y pegar.

using System; 
using System.Reflection; 
using System.CodeDom.Compiler; 
using Microsoft.CSharp; 

void Main() 
{ 
    StringBuilder dc = new StringBuilder(512); 
    dc.Append("public class FileRow"); 
    dc.Append("{"); 
    //dc.Append("[FileHelpers.FieldQuoted('\"', QuoteMode.OptionalForBoth)]"); 
    dc.Append("public string Borrower_First_Name;"); 
    //dc.Append("[FileHelpers.FieldQuoted('\"', QuoteMode.OptionalForBoth)]"); 
    dc.Append("public string Borrower_Last_Name;"); 
    dc.Append("public string Borrower_Email;"); 
    dc.Append("}"); 

    CompilerResults compiledResult = CompileScript(dc.ToString()); 

    if (compiledResult.Errors.HasErrors) 
    { 
     Console.WriteLine (compiledResult.Errors[0].ErrorText); 
     throw new InvalidOperationException("Invalid Expression syntax"); 
    } 

    Assembly assembly = compiledResult.CompiledAssembly; 

    // This is just for testing purposes. 
    FieldInfo field = assembly.GetType("FileRow").GetField("Borrower_First_Name");   
    Console.WriteLine (field.Name);   
    Console.WriteLine (field.FieldType); 
} 

public static CompilerResults CompileScript(string source) 
{ 
    CompilerParameters parms = new CompilerParameters(); 

    parms.GenerateExecutable = false; 
    parms.GenerateInMemory = true; 
    parms.IncludeDebugInformation = false; 

    CodeDomProvider compiler = CSharpCodeProvider.CreateProvider("CSharp"); 

    return compiler.CompileAssemblyFromSource(parms, source); 
} 
+0

Gracias, lo intentaré en breve. Necesito hacer algo como esto para usarlo: FileRow fileRow = ParseFileHelperDataRow (rowID, lineContents, sqlConn); Así que una vez que haga lo que muestra arriba, ¿usaría la reflexión para crear mi objeto? – NealWalters

+0

Después de hacer lo que mostré, ahora tendrá un objeto en su conjunto. Si miras a continuación mi ejemplo, muestra cómo puedes llamar propiedades en ese objeto, pero también puedes asignar propiedades/campos, invocar métodos sobre él. Por ejemplo, si tiene un método, puede obtener ese método assembly.GetType ("FileRow"). GetMethod ("MyMethod); y luego invoca invoke sobre él. La variable de ensamblaje que obtiene está completamente compilada con su código y puede hacer con ella cualquier cosa como los objetos regulares/código compilado. –

+0

Así que necesito completar mi objeto con valores, antes de intentar extraer esos valores; Probaré algo como esto: Objeto myObject = assembly.GetType ("FileRow"); myObject = ParseFileHelperDataRow (rowID, lineContents, sqlConn); – NealWalters

2

También puede usar CodeDOM para generar su clase dinámicamente. Para obtener más información, visite

http://msdn.microsoft.com/en-us/library/ms404245.aspx

+0

Eso parece fácil; Ni siquiera he oído hablar de eso ... ¿Puede hacer los atributos también, supongo? – NealWalters

+0

Veo que también está usando Streamwriter para escribir en el disco. ¿Puedo simplemente crear la clase y usarla en mi código sin escribir en el disco? – NealWalters

+0

Sí, podemos usar la propiedad CustomAttributes. – Ramesh

Cuestiones relacionadas