【问题标题】:How to dynamically create a class?如何动态创建一个类?
【发布时间】:2010-10-05 09:04:00
【问题描述】:

我有一个如下所示的课程:

public class Field
{
    public string FieldName;
    public string FieldType;
}

还有一个带有值的对象List<Field>

{"EmployeeID","int"},
{"EmployeeName","String"},
{"Designation","String"}

我想创建一个如下所示的类:

Class DynamicClass
{
    int EmployeeID,
    String EmployeeName,
    String Designation
}

有没有办法做到这一点?

我希望它在运行时生成。我不希望物理 CS 文件驻留在我的文件系统中。

【问题讨论】:

  • 你想在运行时使用那个类还是只生成文件?
  • 我希望它在运行时生成。我不希望物理 CS 文件驻留在我的文件系统中。很抱歉之前没有提到。
  • 您能大致了解一下您打算在这门课上做什么吗?
  • @Justin 实现了运行时解析的接口,例如。
  • 可以将其提供给System.ServiceModel.ChannelFactory<MyDynamicInterface>

标签: c# .net reflection.emit dynamic-class-creation


【解决方案1】:

是的,您可以为此使用 System.Reflection.Emit 命名空间。如果您没有这方面的经验,这不是直截了当的,但它肯定是可能的。

编辑:这段代码可能有缺陷,但它会给你一个大致的想法,并希望为实现目标有个良好的开端。

using System;
using System.Reflection;
using System.Reflection.Emit;

namespace TypeBuilderNamespace
{
    public static class MyTypeBuilder
    {
        public static void CreateNewObject()
        {
            var myType = CompileResultType();
            var myObject = Activator.CreateInstance(myType);
        }
        public static Type CompileResultType()
        {
            TypeBuilder tb = GetTypeBuilder();
            ConstructorBuilder constructor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);

            // NOTE: assuming your list contains Field objects with fields FieldName(string) and FieldType(Type)
            foreach (var field in yourListOfFields)
                CreateProperty(tb, field.FieldName, field.FieldType);

            Type objectType = tb.CreateType();
            return objectType;
        }

        private static TypeBuilder GetTypeBuilder()
        {
            var typeSignature = "MyDynamicType";
            var an = new AssemblyName(typeSignature);
            AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
            ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
            TypeBuilder tb = moduleBuilder.DefineType(typeSignature,
                    TypeAttributes.Public |
                    TypeAttributes.Class |
                    TypeAttributes.AutoClass |
                    TypeAttributes.AnsiClass |
                    TypeAttributes.BeforeFieldInit |
                    TypeAttributes.AutoLayout,
                    null);
            return tb;
        }

        private static void CreateProperty(TypeBuilder tb, string propertyName, Type propertyType)
        {
            FieldBuilder fieldBuilder = tb.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);

            PropertyBuilder propertyBuilder = tb.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
            MethodBuilder getPropMthdBldr = tb.DefineMethod("get_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, propertyType, Type.EmptyTypes);
            ILGenerator getIl = getPropMthdBldr.GetILGenerator();

            getIl.Emit(OpCodes.Ldarg_0);
            getIl.Emit(OpCodes.Ldfld, fieldBuilder);
            getIl.Emit(OpCodes.Ret);

            MethodBuilder setPropMthdBldr =
                tb.DefineMethod("set_" + propertyName,
                  MethodAttributes.Public |
                  MethodAttributes.SpecialName |
                  MethodAttributes.HideBySig,
                  null, new[] { propertyType });

            ILGenerator setIl = setPropMthdBldr.GetILGenerator();
            Label modifyProperty = setIl.DefineLabel();
            Label exitSet = setIl.DefineLabel();

            setIl.MarkLabel(modifyProperty);
            setIl.Emit(OpCodes.Ldarg_0);
            setIl.Emit(OpCodes.Ldarg_1);
            setIl.Emit(OpCodes.Stfld, fieldBuilder);

            setIl.Emit(OpCodes.Nop);
            setIl.MarkLabel(exitSet);
            setIl.Emit(OpCodes.Ret);

            propertyBuilder.SetGetMethod(getPropMthdBldr);
            propertyBuilder.SetSetMethod(setPropMthdBldr);
        }
    }
}

【讨论】:

  • 太棒了!能否也告诉我如何创建 CompileResultType() 方法返回的类型的对象?
  • 您可以为此使用 System.Activator。我会用一个例子来更新答案。
  • 还要注意,您必须使用反射来检查、读取和更新动态类型中的字段。如果你想要智能感知而不需要反射,你必须有一个静态基类或接口,你的动态类继承自并可以转换为。在这种情况下,您可以修改 GetTypeBuilder() 方法并更改 moduleBuilder.DefineType 调用以包含静态类型作为最后一个参数(现在为 null)
  • 有人可以解释如何在创建对象后使用它
  • @bugz 使用上面的代码创建类,然后在基类中添加这个方法: public void SetValue(string name, T value) { GetType().GetProperty( name).SetValue(this, value); }
【解决方案2】:

这需要一些工作,但肯定不是不可能的。

我所做的是:

  • 在字符串中创建 C# 源代码(无需写入文件),
  • 通过Microsoft.CSharp.CSharpCodeProvider (CompileAssemblyFromSource) 运行它
  • 找到生成的类型
  • 并创建该类型的实例 (Activator.CreateInstance)

这样您就可以处理您已经知道的 C# 代码,而不必发出 MSIL。

但是,如果您的类实现了某个接口(或从某个基类派生),则此方法效果最好,否则调用代码(阅读:编译器)如何知道将在运行时生成的该类?

【讨论】:

  • 可能想看看这个讨论:reflection-emit-vs-codedom
  • @nawfal ,ashwnacharya,希望在运行时动态生成其类,其成员最初包含在列表中。我认为即使在运行时生成的文件中也不会是一个好的性能解决方案。
【解决方案3】:

您也可以使用DynamicObject动态创建一个类。

public class DynamicClass : DynamicObject
{
    private Dictionary<string, KeyValuePair<Type, object>> _fields;

    public DynamicClass(List<Field> fields)
    {
        _fields = new Dictionary<string, KeyValuePair<Type, object>>();
        fields.ForEach(x => _fields.Add(x.FieldName,
            new KeyValuePair<Type, object>(x.FieldType, null)));
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        if (_fields.ContainsKey(binder.Name))
        {
            var type = _fields[binder.Name].Key;
            if (value.GetType() == type)
            {
                _fields[binder.Name] = new KeyValuePair<Type, object>(type, value);
                return true;
            }
            else throw new Exception("Value " + value + " is not of type " + type.Name);
        }
        return false;
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        result = _fields[binder.Name].Value;
        return true;
    }
}

我将所有类字段连同它们的类型和值一起存储在字典_fields 中。这两种方法都可以获取或设置某些属性的值。您必须使用 dynamic 关键字来创建此类的实例。

你的例子的用法:

var fields = new List<Field>() { 
    new Field("EmployeeID", typeof(int)),
    new Field("EmployeeName", typeof(string)),
    new Field("Designation", typeof(string)) 
};

dynamic obj = new DynamicClass(fields);

//set
obj.EmployeeID = 123456;
obj.EmployeeName = "John";
obj.Designation = "Tech Lead";

obj.Age = 25;             //Exception: DynamicClass does not contain a definition for 'Age'
obj.EmployeeName = 666;   //Exception: Value 666 is not of type String

//get
Console.WriteLine(obj.EmployeeID);     //123456
Console.WriteLine(obj.EmployeeName);   //John
Console.WriteLine(obj.Designation);    //Tech Lead

编辑:这是我的班级Field的样子:

public class Field
{
    public Field(string name, Type type)
    {
        this.FieldName = name;
        this.FieldType = type;
    }

    public string FieldName;

    public Type FieldType;
}

【讨论】:

  • 我喜欢这种方法,直到我需要使用构造函数初始化字段。即dynamic obj = new DynamicClass(fields){EmployeeId=123456;EmployeeName = "John"; Designation = "Tech Lead";}这样做真的很棒。
  • 另请注意,这种方法会强制对所有值类型字段进行装箱。
【解决方案4】:

我知道我重新打开了这个旧任务,但是使用 c# 4.0 这个任务绝对没有痛苦。

dynamic expando = new ExpandoObject();
expando.EmployeeID=42;
expando.Designation="unknown";
expando.EmployeeName="curt"

//or more dynamic
AddProperty(expando, "Language", "English");

更多见 https://www.oreilly.com/learning/building-c-objects-dynamically

【讨论】:

【解决方案5】:

我不知道这种动态类的预期用途,并且可以完成代码生成和运行时编译,但需要一些努力。 也许Anonymous Types 会帮助你,比如:

var v = new { EmployeeID = 108, EmployeeName = "John Doe" };

【讨论】:

  • 您不能对字段名称进行硬编码。他正在向他们提供他的Field.FieldName。必须对字段名称进行硬编码违背了目的。如果你必须这样做,你不妨创建类。
【解决方案6】:

你想看看CodeDOM。它允许定义代码元素并编译它们。引用 MSDN:

...这个对象图可以呈现为 使用 CodeDOM 代码的源代码 支持编程的生成器 语言。也可以使用 CodeDOM 将源代码编译成二进制文件 组装。

【讨论】:

  • 我希望它在运行时生成。我不希望物理 CS 文件驻留在我的文件系统中。很抱歉之前没有提到。
  • @ashwnacharya:您可以使用 CodeDOM 来生成源文件并在运行时编译它!
  • 但请注意,CodeDOM 编译器采用原始字符串,因此您可能需要考虑类似于 XSS 和 SQL 注入中使用的“代码插入攻击”。
【解决方案7】:

您也可以使用DynamicExpressions动态创建一个类。

由于 'Dictionary's 具有紧凑的初始化程序并处理键冲突,因此您需要执行这样的操作。

  var list = new Dictionary<string, string> {
    {
      "EmployeeID",
      "int"
    }, {
      "EmployeeName",
      "String"
    }, {
      "Birthday",
      "DateTime"
    }
  };

或者您可能希望使用 JSON 转换器将您的序列化字符串对象构造成可管理的对象。

然后使用 System.Linq.Dynamic;

  IEnumerable<DynamicProperty> props = list.Select(property => new DynamicProperty(property.Key, Type.GetType(property.Value))).ToList();

  Type t = DynamicExpression.CreateClass(props);

剩下的只是使用 System.Reflection。

  object obj = Activator.CreateInstance(t);
  t.GetProperty("EmployeeID").SetValue(obj, 34, null);
  t.GetProperty("EmployeeName").SetValue(obj, "Albert", null);
  t.GetProperty("Birthday").SetValue(obj, new DateTime(1976, 3, 14), null);
}  

【讨论】:

    【解决方案8】:

    正如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;
            }
        }
    }
    

    【讨论】:

      【解决方案9】:

      根据@danijels 的回答,在VB.NET 中动态创建一个类:

      Imports System.Reflection
      Imports System.Reflection.Emit
      
      Public Class ObjectBuilder
      
      Public Property myType As Object
      Public Property myObject As Object
      
      Public Sub New(fields As List(Of Field))
          myType = CompileResultType(fields)
          myObject = Activator.CreateInstance(myType)
      End Sub
      
      Public Shared Function CompileResultType(fields As List(Of Field)) As Type
          Dim tb As TypeBuilder = GetTypeBuilder()
          Dim constructor As ConstructorBuilder = tb.DefineDefaultConstructor(MethodAttributes.[Public] Or MethodAttributes.SpecialName Or MethodAttributes.RTSpecialName)
      
          For Each field In fields
              CreateProperty(tb, field.Name, field.Type)
          Next
      
          Dim objectType As Type = tb.CreateType()
          Return objectType
      End Function
      
      Private Shared Function GetTypeBuilder() As TypeBuilder
          Dim typeSignature = "MyDynamicType"
          Dim an = New AssemblyName(typeSignature)
          Dim assemblyBuilder As AssemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run)
          Dim moduleBuilder As ModuleBuilder = assemblyBuilder.DefineDynamicModule("MainModule")
          Dim tb As TypeBuilder = moduleBuilder.DefineType(typeSignature, TypeAttributes.[Public] Or TypeAttributes.[Class] Or TypeAttributes.AutoClass Or TypeAttributes.AnsiClass Or TypeAttributes.BeforeFieldInit Or TypeAttributes.AutoLayout, Nothing)
          Return tb
      End Function
      
      Private Shared Sub CreateProperty(tb As TypeBuilder, propertyName As String, propertyType As Type)
          Dim fieldBuilder As FieldBuilder = tb.DefineField("_" & propertyName, propertyType, FieldAttributes.[Private])
      
          Dim propertyBuilder As PropertyBuilder = tb.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, Nothing)
          Dim getPropMthdBldr As MethodBuilder = tb.DefineMethod("get_" & propertyName, MethodAttributes.[Public] Or MethodAttributes.SpecialName Or MethodAttributes.HideBySig, propertyType, Type.EmptyTypes)
          Dim getIl As ILGenerator = getPropMthdBldr.GetILGenerator()
      
          getIl.Emit(OpCodes.Ldarg_0)
          getIl.Emit(OpCodes.Ldfld, fieldBuilder)
          getIl.Emit(OpCodes.Ret)
      
          Dim setPropMthdBldr As MethodBuilder = tb.DefineMethod("set_" & propertyName, MethodAttributes.[Public] Or MethodAttributes.SpecialName Or MethodAttributes.HideBySig, Nothing, {propertyType})
      
          Dim setIl As ILGenerator = setPropMthdBldr.GetILGenerator()
          Dim modifyProperty As Label = setIl.DefineLabel()
          Dim exitSet As Label = setIl.DefineLabel()
      
          setIl.MarkLabel(modifyProperty)
          setIl.Emit(OpCodes.Ldarg_0)
          setIl.Emit(OpCodes.Ldarg_1)
          setIl.Emit(OpCodes.Stfld, fieldBuilder)
      
          setIl.Emit(OpCodes.Nop)
          setIl.MarkLabel(exitSet)
          setIl.Emit(OpCodes.Ret)
      
          propertyBuilder.SetGetMethod(getPropMthdBldr)
          propertyBuilder.SetSetMethod(setPropMthdBldr)
      End Sub
      
      End Class
      

      【讨论】:

        【解决方案10】:

        对于那些想要创建一个动态类只是属性(即 POCO),并创建这个类的列表。使用稍后提供的代码,这将创建一个动态类并创建一个列表。

        var properties = new List<DynamicTypeProperty>()
        {
            new DynamicTypeProperty("doubleProperty", typeof(double)),
            new DynamicTypeProperty("stringProperty", typeof(string))
        };
        
        // create the new type
        var dynamicType = DynamicType.CreateDynamicType(properties);
        // create a list of the new type
        var dynamicList = DynamicType.CreateDynamicList(dynamicType);
        
        // get an action that will add to the list
        var addAction = DynamicType.GetAddAction(dynamicList);
        
        // call the action, with an object[] containing parameters in exact order added
        addAction.Invoke(new object[] {1.1, "item1"});
        addAction.Invoke(new object[] {2.1, "item2"});
        addAction.Invoke(new object[] {3.1, "item3"});
        

        这是前面代码使用的类。

        注意:您还需要引用 Microsoft.CodeAnalysis.CSharp 库。

               /// <summary>
            /// A property name, and type used to generate a property in the dynamic class.
            /// </summary>
            public class DynamicTypeProperty
            {
                public DynamicTypeProperty(string name, Type type)
                {
                    Name = name;
                    Type = type;
                }
                public string Name { get; set; }
                public Type Type { get; set; }
            }
        
           public static class DynamicType
            {
                /// <summary>
                /// Creates a list of the specified type
                /// </summary>
                /// <param name="type"></param>
                /// <returns></returns>
                public static IEnumerable<object> CreateDynamicList(Type type)
                {
                    var listType = typeof(List<>);
                    var dynamicListType = listType.MakeGenericType(type);
                    return (IEnumerable<object>) Activator.CreateInstance(dynamicListType);
                }
        
                /// <summary>
                /// creates an action which can be used to add items to the list
                /// </summary>
                /// <param name="listType"></param>
                /// <returns></returns>
                public static Action<object[]> GetAddAction(IEnumerable<object> list)
                {
                    var listType = list.GetType();
                    var addMethod = listType.GetMethod("Add");
                    var itemType = listType.GenericTypeArguments[0];
                    var itemProperties = itemType.GetProperties();
        
                    var action = new Action<object[]>((values) =>
                    {
                        var item = Activator.CreateInstance(itemType);
        
                        for(var i = 0; i < values.Length; i++)
                        {
                            itemProperties[i].SetValue(item, values[i]);
                        }
        
                        addMethod.Invoke(list, new []{item});
                    });
        
                    return action;
                }
        
                /// <summary>
                /// Creates a type based on the property/type values specified in the properties
                /// </summary>
                /// <param name="properties"></param>
                /// <returns></returns>
                /// <exception cref="Exception"></exception>
                public static Type CreateDynamicType(IEnumerable<DynamicTypeProperty> properties)
                {
                    StringBuilder classCode = new StringBuilder();
        
                    // Generate the class code
                    classCode.AppendLine("using System;");
                    classCode.AppendLine("namespace Dexih {");
                    classCode.AppendLine("public class DynamicClass {");
        
                    foreach (var property in properties)
                    {
                        classCode.AppendLine($"public {property.Type.Name} {property.Name} {{get; set; }}");
                    }
                    classCode.AppendLine("}");
                    classCode.AppendLine("}");
        
                    var syntaxTree = CSharpSyntaxTree.ParseText(classCode.ToString());
        
                    var references = new MetadataReference[]
                    {
                        MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location),
                        MetadataReference.CreateFromFile(typeof(DictionaryBase).GetTypeInfo().Assembly.Location)
                    };
        
                    var compilation = CSharpCompilation.Create("DynamicClass" + Guid.NewGuid() + ".dll",
                        syntaxTrees: new[] {syntaxTree},
                        references: references,
                        options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
        
                    using (var ms = new MemoryStream())
                    {
                        var result = compilation.Emit(ms);
        
                        if (!result.Success)
                        {
                            var failures = result.Diagnostics.Where(diagnostic =>
                                diagnostic.IsWarningAsError ||
                                diagnostic.Severity == DiagnosticSeverity.Error);
        
                            var message = new StringBuilder();
        
                            foreach (var diagnostic in failures)
                            {
                                message.AppendFormat("{0}: {1}", diagnostic.Id, diagnostic.GetMessage());
                            }
        
                            throw new Exception($"Invalid property definition: {message}.");
                        }
                        else
                        {
        
                            ms.Seek(0, SeekOrigin.Begin);
                            var assembly = System.Runtime.Loader.AssemblyLoadContext.Default.LoadFromStream(ms);
                            var dynamicType = assembly.GetType("Dexih.DynamicClass");
                            return dynamicType;
                        }
                    }
                }
            }
        

        【讨论】:

        • 一段很棒的代码。是否可以在动态列表上也使用 AddRange,最终一次添加多条记录?
        【解决方案11】:

        您可以考虑使用可以完成这项工作的动态模块和类。唯一的缺点是它仍然加载在应用程序域中。但是随着使用 .NET 框架的版本,这可能会改变。 .NET 4.0 支持可收集的动态程序集,因此您可以动态地重新创建类/类型。

        【讨论】:

          【解决方案12】:

          哇!谢谢你的回答!我向它添加了一些功能来创建一个“数据表到 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”子中,我改变了:

              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
          

          【讨论】:

            【解决方案13】:

            您可以使用 CSharpProvider:

            var code = @"
                public class Abc {
                   public string Get() { return ""abc""; }
                }
            ";
            
            var options = new CompilerParameters();
            options.GenerateExecutable = false;
            options.GenerateInMemory = false;
            
            var provider = new CSharpCodeProvider();
            var compile = provider.CompileAssemblyFromSource(options, code);
            
            var type = compile.CompiledAssembly.GetType("Abc");
            var abc = Activator.CreateInstance(type);
            
            var method = type.GetMethod("Get");
            var result = method.Invoke(abc, null);
            
            Console.WriteLine(result); //output: abc
            

            【讨论】:

              【解决方案14】:

              您可以使用 System.Runtime.Remoting.Proxies.RealProxy。它将允许您使用“普通”代码而不是低级汇编类型的东西。

              请参阅 RealProxy 对此问题的回答以获取一个很好的示例:

              How do I intercept a method call in C#?

              【讨论】:

                【解决方案15】:

                Runtime Code Generation with JVM and CLR - 彼得·塞斯托夫特

                为对此类编程真正感兴趣的人工作。

                我给你的建议是,如果你声明了一些东西,尽量避免使用字符串,所以如果你有类 Field,最好使用类 System.Type 来存储字段类型而不是字符串。 为了获得最佳解决方案而不是创建新类,请尝试使用已创建的 FiledInfo 而不是创建新类。

                【讨论】:

                • 链接失效:-1
                • 格伦:快速谷歌搜索发现了一个工作链接:pdfs.semanticscholar.org/326a/…
                • @AndreasPardeike 谢谢,我在文章中修复了它。
                猜你喜欢
                • 2011-09-29
                • 1970-01-01
                • 2015-12-29
                • 2013-11-03
                • 2016-01-24
                • 2017-04-15
                • 2021-11-27
                • 1970-01-01
                • 2018-03-09
                相关资源
                最近更新 更多