我有一个类,它看起来像这样:
public class Field
{
public string FieldName;
public string FieldType;
}
和一个对象列表<字段>值:
{"EmployeeID","int"},
{"EmployeeName","String"},
{"Designation","String"}
我想创建一个类,看起来像这样:
Class DynamicClass
{
int EmployeeID,
String EmployeeName,
String Designation
}
有什么办法可以做到吗?
我希望它在运行时生成。我不希望在文件系统中驻留一个物理CS文件。
哇!谢谢你的回答!我添加了一些功能,以创建一个“数据表到json”的转换器,我与您分享。
Public Shared Sub dt2json(ByVal _dt As DataTable, ByVal _sb As StringBuilder)
Dim t As System.Type
Dim oList(_dt.Rows.Count - 1) As Object
Dim jss As New JavaScriptSerializer()
Dim i As Integer = 0
t = CompileResultType(_dt)
For Each dr As DataRow In _dt.Rows
Dim o As Object = Activator.CreateInstance(t)
For Each col As DataColumn In _dt.Columns
setvalue(o, col.ColumnName, dr.Item(col.ColumnName))
Next
oList(i) = o
i += 1
Next
jss = New JavaScriptSerializer()
jss.Serialize(oList, _sb)
End Sub
在"compileresulttype" sub中,我修改了:
For Each column As DataColumn In _dt.Columns
CreateProperty(tb, column.ColumnName, column.DataType)
Next
Private Shared Sub setvalue(ByVal _obj As Object, ByVal _propName As String, ByVal _propValue As Object)
Dim pi As PropertyInfo
pi = _obj.GetType.GetProperty(_propName)
If pi IsNot Nothing AndAlso pi.CanWrite Then
If _propValue IsNot DBNull.Value Then
pi.SetValue(_obj, _propValue, Nothing)
Else
Select Case pi.PropertyType.ToString
Case "System.String"
pi.SetValue(_obj, String.Empty, Nothing)
Case Else
'let the serialiser use javascript "null" value.
End Select
End If
End If
End Sub
正如Hans所建议的,您可以使用Roslyn动态创建类。
完整的资料来源:
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
namespace RoslynDemo1
{
class Program
{
static void Main(string[] args)
{
var fields = new List<Field>()
{
new Field("EmployeeID","int"),
new Field("EmployeeName","String"),
new Field("Designation","String")
};
var employeeClass = CreateClass(fields, "Employee");
dynamic employee1 = Activator.CreateInstance(employeeClass);
employee1.EmployeeID = 4213;
employee1.EmployeeName = "Wendy Tailor";
employee1.Designation = "Engineering Manager";
dynamic employee2 = Activator.CreateInstance(employeeClass);
employee2.EmployeeID = 3510;
employee2.EmployeeName = "John Gibson";
employee2.Designation = "Software Engineer";
Console.WriteLine($"{employee1.EmployeeName}");
Console.WriteLine($"{employee2.EmployeeName}");
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
public static Type CreateClass(List<Field> fields, string newClassName, string newNamespace = "Magic")
{
var fieldsCode = fields
.Select(field => $"public {field.FieldType} {field.FieldName};")
.ToString(Environment.NewLine);
var classCode = $@"
using System;
namespace {newNamespace}
{{
public class {newClassName}
{{
public {newClassName}()
{{
}}
{fieldsCode}
}}
}}
".Trim();
classCode = FormatUsingRoslyn(classCode);
var assemblies = new[]
{
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
};
/*
var assemblies = AppDomain
.CurrentDomain
.GetAssemblies()
.Where(a => !string.IsNullOrEmpty(a.Location))
.Select(a => MetadataReference.CreateFromFile(a.Location))
.ToArray();
*/
var syntaxTree = CSharpSyntaxTree.ParseText(classCode);
var compilation = CSharpCompilation
.Create(newNamespace)
.AddSyntaxTrees(syntaxTree)
.AddReferences(assemblies)
.WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
using (var ms = new MemoryStream())
{
var result = compilation.Emit(ms);
//compilation.Emit($"C:\\Temp\\{newNamespace}.dll");
if (result.Success)
{
ms.Seek(0, SeekOrigin.Begin);
Assembly assembly = Assembly.Load(ms.ToArray());
var newTypeFullName = $"{newNamespace}.{newClassName}";
var type = assembly.GetType(newTypeFullName);
return type;
}
else
{
IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic =>
diagnostic.IsWarningAsError ||
diagnostic.Severity == DiagnosticSeverity.Error);
foreach (Diagnostic diagnostic in failures)
{
Console.Error.WriteLine("{0}: {1}", diagnostic.Id, diagnostic.GetMessage());
}
return null;
}
}
}
public static string FormatUsingRoslyn(string csCode)
{
var tree = CSharpSyntaxTree.ParseText(csCode);
var root = tree.GetRoot().NormalizeWhitespace();
var result = root.ToFullString();
return result;
}
}
public class Field
{
public string FieldName;
public string FieldType;
public Field(string fieldName, string fieldType)
{
FieldName = fieldName;
FieldType = fieldType;
}
}
public static class Extensions
{
public static string ToString(this IEnumerable<string> list, string separator)
{
string result = string.Join(separator, list);
return result;
}
}
}