Can I build a class as shown below dynamically using reflection? There are no methods, just public variables, some have custom attributes.
Is the .Emit method required (from what I've seen, "Emit" looks a little challenging).
I'm using software from www.FileHelpers.net, and it requires a class. All my file definitions are in a database table, and I'd like to make everything more dynamic (i.e. no code changes when a new column appears in the file).
[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;
}
Update 1: Based on Vlad's answer below I needed to reference DLL, here's how I did it:
// need to reference the FileHelpers.dll from our own .exe directory
string diskFilenameFileHelpersDLL =
System.IO.Path.GetDirectoryName(
System.Reflection.Assembly.GetExecutingAssembly().Location) +
@"\FileHelpers.dll";
Update 2: Also, after doing what Vlad suggested, this is how I call FileHelper and loop through the results. I'll probably transfer the data to a list.
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);
}
If you have your code stored in the database as string what you can do something like this to create an assembly:
The reason I commented out attributes because I don't have namespace for them. I am assuming you have namespace and you will need to add it to your code to compile.
Code works in LINQPad, so you can just copy and paste.
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);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With