วิธีสร้างคลาสแบบไดนามิกได้อย่างไร


223

ฉันมีชั้นเรียนที่มีลักษณะเช่นนี้:

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 ทางกายภาพที่อยู่ในระบบไฟล์ของฉัน


4
คุณต้องการใช้คลาสนั้นในรันไทม์หรือสร้างไฟล์เท่านั้น
Damian Leszczyński - Vash

ฉันต้องการสิ่งนี้ที่จะสร้างขึ้นในรันไทม์ ฉันไม่ต้องการไฟล์ CS ทางกายภาพที่อยู่ในระบบไฟล์ของฉัน ขออภัยที่ไม่ได้กล่าวถึงก่อนหน้านี้
ashwnacharya

16
คุณช่วยบอกให้เราทราบอย่างคร่าว ๆ ว่าคุณตั้งใจจะทำอะไรกับคลาสนี้?
Justin

3
@Justin ใช้อินเทอร์เฟซที่แก้ไขรันไทม์ตัวอย่างเช่น
AgentFire

เราสามารถเลี้ยงมันได้System.ServiceModel.ChannelFactory<MyDynamicInterface>
Ilya Semenov

คำตอบ:


298

ใช่คุณสามารถใช้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);
        }
    }
}

2
น่ากลัว !! คุณสามารถบอกวิธีสร้างวัตถุประเภทที่ส่งคืนโดยวิธี CompileResultType () ได้หรือไม่
ashwnacharya

4
คุณสามารถใช้ System.Activator สำหรับสิ่งนั้น ฉันจะอัปเดตคำตอบด้วยตัวอย่าง
danijels

4
โปรดทราบว่าคุณจะต้องใช้การสะท้อนเพื่อตรวจสอบอ่านและอัปเดตฟิลด์ในประเภทไดนามิกของคุณ หากคุณต้องการความเป็น Intellisense และไม่มีการสะท้อนคุณต้องมีคลาสฐานแบบคงที่หรือส่วนต่อประสานที่คลาสแบบไดนามิกของคุณสืบทอดมาจากและสามารถใช้งานได้ ในกรณีนั้นคุณสามารถปรับเปลี่ยนวิธี GetTypeBuilder () และเปลี่ยน moduleBuilder.DefineType การโทรเพื่อรวมประเภทคงที่เป็นพารามิเตอร์สุดท้าย (ตอนนี้เป็นโมฆะ)
danijels

2
ใครบางคนสามารถอธิบายวิธีการใช้วัตถุหลังจากที่สร้างขึ้นได้
HELP_ME

3
@bugz ใช้รหัสด้านบนเพื่อสร้างคลาสจากนั้นในคลาสฐานคุณสามารถเพิ่มวิธีนี้: โมฆะสาธารณะ SetValue <T> (ชื่อสตริง, ค่า T) {GetType (). GetProperty (ชื่อ). SetValue (นี่ค่า ); }
stricq

71

จะต้องใช้งานบ้าง แต่ก็เป็นไปไม่ได้แน่นอน

สิ่งที่ฉันทำคือ:

  • สร้างซอร์ส C # ในสตริง (ไม่จำเป็นต้องเขียนลงไฟล์)
  • เรียกใช้ผ่านทางMicrosoft.CSharp.CSharpCodeProvider(CompileAssemblyFromSource)
  • ค้นหาประเภทที่สร้างขึ้น
  • และสร้างอินสแตนซ์ของ Type ( Activator.CreateInstance)

วิธีนี้คุณสามารถจัดการกับรหัส C # ที่คุณรู้อยู่แล้วแทนที่จะต้องปล่อย MSIL

แต่วิธีนี้จะได้ผลดีที่สุดหากคลาสของคุณใช้อินเทอร์เฟซบางตัว (หรือได้มาจาก baseclass บางส่วน) มิฉะนั้นแล้วรหัสการโทร (อ่าน: คอมไพเลอร์) จะรู้ได้อย่างไรว่าคลาสนั้นจะถูกสร้างขึ้นที่รันไทม์?


7
อาจต้องการดูการสนทนานี้: reflection-emit-vs-codedom
nawfal

1
@nawfal, ashwnacharya ต้องการสร้างแบบไดนามิกที่รันไทม์คลาสกับสมาชิกที่มีอยู่ในรายการ ฉันไม่คิดว่าจะนำมันไปวางไว้ในไฟล์ที่สร้างไว้ตอนรันไทม์ซึ่งจะเป็นโซลูชันที่มีประสิทธิภาพดี
sodjsn26fr

39

นอกจากนี้คุณยังสามารถสร้างแบบไดนามิกระดับโดยใช้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;
}

1
ฉันชอบวิธีนี้จนกว่าฉันจะต้องเริ่มต้นเขตข้อมูลด้วยตัวสร้าง เช่นdynamic obj = new DynamicClass(fields){EmployeeId=123456;EmployeeName = "John"; Designation = "Tech Lead";}มันจะเป็นการดีที่จะทำสิ่งนี้
rey_coder

14

ฉันไม่ทราบว่าการใช้งานที่ตั้งใจของคลาสแบบไดนามิกเช่นนั้นและการสร้างรหัสและการรวบรวมเวลาทำงานสามารถทำได้ แต่ใช้ความพยายาม บางทีประเภทไม่ระบุชื่ออาจช่วยคุณได้เช่น:

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

7
คุณไม่สามารถเขียนโค้ดชื่อฟิลด์ได้ยาก Field.FieldNameเขาให้พวกเขามีของเขา ต้องมีรหัสอย่างหนักชื่อเขตข้อมูลเอาชนะวัตถุประสงค์ หากคุณต้องทำเช่นนั้นคุณอาจสร้างชั้นเรียนได้เช่นกัน
toddmo

14

ฉันรู้ว่าฉันเปิดงานเก่านี้อีกครั้ง แต่ด้วย 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


ใช่ แต่คุณสูญเสียความปลอดภัยประเภทที่นี่ เราสามารถทำสิ่งที่คล้ายกันในขณะที่รักษาความปลอดภัยประเภท?
toughQuestions

9

คุณต้องการที่จะมองไปที่CodeDOM จะช่วยให้การกำหนดองค์ประกอบของรหัสและรวบรวมพวกเขา การอ้างอิง MSDN:

... กราฟวัตถุนี้สามารถแสดงผลเป็นซอร์สโค้ดโดยใช้ตัวสร้างโค้ด CodeDOM สำหรับภาษาการเขียนโปรแกรมที่รองรับ CodeDOM ยังสามารถใช้เพื่อรวบรวมซอร์สโค้ดเป็นชุดประกอบแบบไบนารี


ฉันต้องการสิ่งนี้ที่จะสร้างขึ้นในรันไทม์ ฉันไม่ต้องการไฟล์ CS ทางกายภาพที่อยู่ในระบบไฟล์ของฉัน ขออภัยที่ไม่ได้กล่าวถึงก่อนหน้านี้
ashwnacharya

1
@ashwnacharya: คุณสามารถใช้ CodeDOM เพื่อสร้างไฟล์ต้นฉบับและคอมไพล์ไฟล์ตอนรันไทม์!
Hemant

1
อย่างไรก็ตามระวังว่าคอมไพเลอร์ CodeDOM ใช้สตริงดิบและดังนั้นคุณอาจต้องการพิจารณา "การโจมตีการแทรกรหัส" คล้ายกับที่ใช้ในการฉีด XSS และ SQL
cwap

6

ตามคำตอบของ @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

6

คุณยังสามารถสร้างคลาสแบบไดนามิกโดยใช้DynamicExpressions DynamicExpressions

เนื่องจาก 'พจนานุกรมมีพจนานุกรมย่อและจัดการการชนที่สำคัญคุณจะต้องทำสิ่งนี้

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

4

สำหรับผู้ที่ต้องการสร้างคลาสแบบไดนามิกคุณสมบัติเพียง (เช่น 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 ในรายการแบบไดนามิกเพื่อเพิ่มระเบียนหลายรายการพร้อมกัน?
RickyTad

2

คุณสามารถดูได้โดยใช้โมดูลและคลาสแบบไดนามิกที่สามารถทำงานได้ ข้อเสียเพียงอย่างเดียวคือมันยังคงโหลดอยู่ในโดเมนแอป แต่ด้วยเวอร์ชันของ. NET Framework ที่ใช้นั่นอาจเปลี่ยนแปลงได้ .NET 4.0 รองรับแอสเซมบลีแบบไดนามิกที่สะสมได้และด้วยเหตุนี้คุณสามารถสร้างคลาส / ประเภทแบบไดนามิก


2

ว้าว! ขอบคุณสำหรับคำตอบนั้น! ฉันเพิ่มคุณสมบัติบางอย่างเพื่อสร้างตัวแปลง "datatable to 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

0

คุณสามารถใช้ System.Runtime.Remoting.Proxies.RealProxy มันจะช่วยให้คุณใช้รหัส "ปกติ" มากกว่าสิ่งที่ประเภทการชุมนุมระดับต่ำ

ดูคำตอบ RealProxy สำหรับคำถามนี้เพื่อเป็นตัวอย่างที่ดี:

ฉันจะดักการเรียกเมธอดใน C # ได้อย่างไร


-1

Runtime Code Generation with JVM and CLR - Peter Sestoft

เหมาะสำหรับผู้ที่มีความสนใจในการเขียนโปรแกรมประเภทนี้

เคล็ดลับของฉันสำหรับคุณคือถ้าคุณประกาศสิ่งที่พยายามหลีกเลี่ยงสตริงดังนั้นถ้าคุณมีคลาสฟิลด์จะดีกว่าถ้าใช้คลาสSystem.Typeเพื่อเก็บประเภทฟิลด์มากกว่าสตริง และเพื่อแก้ปัญหาที่ดีที่สุดแทนการสร้างคลาสใหม่ให้ลองใช้คลาสที่สร้างFiledInfoแทนการสร้างใหม่


2
ลิงก์ตาย: -1
Glenn Slayden

Glenn: googling ที่รวดเร็วเปิดเผยลิงค์ที่ใช้งานได้: pdfs.semanticscholar.org/326a/…
Andreas Pardeike

@AndreasPardeike ขอบคุณฉันซ่อมแซมในบทความ
Glenn Slayden
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.