2012-02-23 25 views
6

Czy mogę zbudować klasę jak pokazano poniżej dynamicznie za pomocą odbicia? Nie ma żadnych metod, tylko zmienne publiczne, niektóre mają niestandardowe atrybuty.Użyj refleksji, aby zbudować klasę (aby zbudować dynamiczną klasę FileHelper)

Czy wymagana jest metoda .Emit (z tego, co widziałem, "Emit" wygląda na nieco trudniejsze).

Używam oprogramowania od www.FileHelpers.net, a to wymaga klasy. Wszystkie moje definicje plików znajdują się w tabeli bazy danych i chciałbym, aby wszystko było bardziej dynamiczne (tj. Żaden kod nie zmienia się, gdy pojawia się nowa kolumna w pliku).

[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; 
} 

Aktualizacja 1: Na podstawie odpowiedzi Vlada poniżej potrzebowałem odwołać DLL, oto jak to zrobiłem:

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

Aktualizacja 2: Ponadto, po tym, co sugeruje Vlad, to w jaki sposób mogę zadzwonić FileHelper i zapętlić wyniki. Prawdopodobnie przeniesie dane do listy.

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

Spójrz na [hello, world ... styl Reflection.Emit!] (Http://blogs.msdn.com/b/joelpob/archive/2004/01/21/61411.aspx) –

+0

Czy emitują konkretnie utworzyć .DLL lub .EXE? Potrzebuję tylko klasy w pamięci, niczego zapisanego na dysku. – NealWalters

+0

Mówiłem, że NIE muszę zapisywać na dysku. – NealWalters

Odpowiedz

2

Jeśli kod przechowywane w bazie danych jako ciąg Co można zrobić coś takiego stworzyć montaż:

Powodem wykomentowane atrybuty bo don” t mają dla nich przestrzeń nazw. Zakładam, że masz przestrzeń nazw i musisz ją dodać do swojego kodu, aby ją skompilować.

Kod działa w LINQPad, więc można po prostu skopiować i wkleić.

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

Dzięki, sprobuję krótko. Potrzebuję zrobić coś takiego, aby go użyć: FileRow fileRow = ParseFileHelperDataRow (rowID, lineContents, sqlConn); Więc kiedy zrobię to, co pokazałeś powyżej, użyję refleksji do stworzenia mojego obiektu? – NealWalters

+0

Po zrobieniu tego, co pokazałem, będziesz mieć teraz w swoim zgromadzeniu przedmiot. Jeśli spojrzysz na mój przykład poniżej, zobaczysz, jak możesz wywoływać właściwości tego obiektu, ale możesz również przypisać właściwości/pola, metody wywołania na nim. Na przykład, jeśli masz metodę, możesz uzyskać tą metodę assembly.GetType ("FileRow") GetMethod ("MyMethod), a następnie wywołaj wywołanie na nim. Zmienna złożenia, którą otrzymujesz, jest w pełni skompilowana do twojego kodu i możesz zrobić z nią wszystko jak zwykłe obiekty/skompilowany kod. –

+0

Więc muszę wypełnić mój obiekt wartościami, zanim spróbuję wyodrębnić te wartości; Spróbuję czegoś takiego: Obiekt myObject = assembly.GetType ("FileRow"); myObject = ParseFileHelperDataRow (rowID, lineContents, sqlConn); – NealWalters

2

Można również użyć CodeDOM do dynamicznego generowania klasy. Aby uzyskać więcej informacji odwiedź

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

+0

To wygląda łatwo; Nawet o tym nie słyszałem ... Czy to też może robić atrybuty? – NealWalters

+0

Widzę, że do zapisu na dysku używa również Streamwitera. Czy mogę po prostu utworzyć klasę i używać jej w moim kodzie bez pisania na dysk? – NealWalters

+0

Tak, możemy użyć właściwości CustomAttributes. – Ramesh

Powiązane problemy