2012-02-23 2 views
6

리플렉션을 사용하여 동적으로 아래 표시된 클래스를 빌드 할 수 있습니까? 메소드가 없으며, 공용 변수 만 있고, 일부는 사용자 정의 속성을 가지고 있습니다.Reflection을 사용하여 클래스 작성 (동적 FileHelper 클래스 작성)

.Emit 메서드가 필요합니까 ("Emit"는 조금 어려워 보입니다).

나는 www.FileHelpers.net에서 소프트웨어를 사용하고 있으며 수업이 필요합니다. 모든 파일 정의가 데이터베이스 테이블에 있으며 모든 것을 동적으로 만들고 싶습니다. 즉, 파일에 새 열이 나타나면 코드가 변경되지 않습니다.

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

업데이트 1 :

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

업데이트 2 : 내가 DLL을 참조하는 데 필요한 아래 블라드의 답변에 따라이 여기에 어떻게 내가 해냈어 또한, 블라드 제안하는 일을 한 후,이 내가 전화하는 방법입니다 FileHelper를 실행하고 결과를 반복합니다. 아마도 데이터를 목록으로 전송할 것입니다.

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

를 살펴 보자 [안녕, 세계 ... Reflection.Emit를 스타일!] (http://blogs.msdn.com/b/joelpob/archive/2004/01/21/61411.aspx) –

+0

방출은 특별히 .DLL 또는 .EXE를 생성합니까? 메모리에 클래스 만 있으면되고 디스크에 저장되는 클래스는 없습니다. – NealWalters

+0

나는 디스크에 저장할 필요가 없다고 말하고 있었다. – NealWalters

답변

2

를 방문 그들에 대한 네임 스페이스가 있습니다. 네임 스페이스가 있다고 가정하고 컴파일 할 코드를 네임 스페이스에 추가해야합니다.

코드는 LINQPad에서 작동하므로 복사하여 붙여 넣기 만하면됩니다.

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

감사합니다. 곧 다시 시도하겠습니다. 이를 사용하려면 다음과 같이해야합니다. FileRow fileRow = rowFindHandler (rowID, lineContents, sqlConn); 그래서 위에서 보여준 것을 한 번 해보면 리플렉션을 사용하여 객체를 만들 것입니까? – NealWalters

+0

당신이 보여준 것을 한 후에 당신은 당신의 집회에서 반대 할 것입니다. 내 예제를 보면, 해당 객체에서 속성을 호출하는 방법을 보여 주지만 속성/필드를 할당하고 메서드를 호출 할 수도 있습니다. 예를 들어 메서드가있는 경우 해당 메서드를 가져올 수 assembly.GetType ("FileRow"). GetMethod ("MyMethod); 그리고 호출 할 호출합니다. 당신이 얻은 어셈블리 변수가 완전히 컴파일 된 코드 및 당신은 아무것도 할 수 있습니다. 정규 객체/컴파일 된 코드와 같습니다. –

+0

그래서 값을 추출하려고하기 전에 개체에 값을 채워야합니다. 나는 다음과 같은 것을 시도 할 것이다 : Object myObject = assembly.GetType ("FileRow"); myObject = ParseFileHelperDataRow (rowID, lineContents, sqlConn); – NealWalters

2

또한 CodeDOM을 사용하여 클래스를 동적으로 생성 할 수 있습니다.

이유는 내가 '돈 때문에이 속성을 주석 : 당신은 당신의 코드가 어셈블리를 만들려면이 같은 일을 할 수있는 문자열로 데이터베이스에 저장 한 경우 자세한 내용은

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

+0

보기가 쉽습니다. 나는 그것조차도 듣지 못했습니다 ... 그것은 제가 생각하는 속성을 할 수 있습니까? – NealWalters

+0

나는 Streamwriter를 사용하여 디스크에 기록하는 것을 볼 수 있습니다. 디스크에 쓰지 않고 클래스를 만들고 코드에서 사용할 수 있습니까? – NealWalters

+0

예, CustomAttributes 속성을 사용할 수 있습니다. – Ramesh