programing

클래스를 동적으로 생성하는 방법은 무엇입니까?

instargram 2023. 5. 2. 22:17
반응형

클래스를 동적으로 생성하는 방법은 무엇입니까?

다음과 같은 수업이 있습니다.

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 파일이 내 파일 시스템에 있는 것을 원하지 않습니다.

예, 사용할 수 있습니다.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);
        }
    }
}

그것은 약간의 노력이 필요하겠지만, 확실히 불가능한 것은 아닙니다.

제가 한 일은 다음과 같습니다.

  • 문자열에 C# 소스를 생성합니다(파일에 쓸 필요 없음).
  • 에서 합니다.Microsoft.CSharp.CSharpCodeProvider를 원본에서 컴파일소스에서컴일
  • 생성된 유형 찾기
  • 그)를 .Activator.CreateInstance)

이렇게 하면 MSIL을 방출하는 대신 이미 알고 있는 C# 코드를 처리할 수 있습니다.

그러나 클래스가 어떤 인터페이스(또는 어떤 기본 클래스에서 파생됨)를 구현하는 경우에는 이것이 가장 잘 작동합니다. 그렇지 않으면 호출 코드(읽기: 컴파일러)가 런타임에 생성될 클래스에 대해 어떻게 알 수 있습니까?

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

이 오래된 작업을 다시 시작하는 것은 알지만 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 를 참조하십시오.

저는 이러한 동적 클래스의 의도된 사용법을 잘 모르고 코드 생성과 런타임 컴파일은 할 수 있지만 약간의 노력이 필요합니다.Anonymous Types가 다음과 같은 도움이 될 수 있습니다.

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

Hans가 제안한 대로 Roslin을 사용하여 동적으로 클래스를 만들 수 있습니다.

전체 소스:

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

당신은 CodeDOM을 보고 싶어합니다.코드 요소를 정의하고 컴파일할 수 있습니다.MSDN 인용:

...이 개체 그래프는 코드를 사용하여 소스 코드로 렌더링할 수 있습니다.지원되는 프로그래밍 언어에 대한 DOM 코드 생성기입니다.코드DOM은 소스 코드를 이진 어셈블리로 컴파일하는 데도 사용할 수 있습니다.

동적 표현식을 사용하여 클래스를 동적으로 만들 수도 있습니다.

'Dictionary'에는 콤팩트 이니셜라이저가 있고 키 충돌을 처리하기 때문에 이런 작업이 필요합니다.

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

또는 JSON 변환기를 사용하여 직렬화된 문자열 개체를 관리 가능한 개체로 구성할 수도 있습니다.

그런 다음 시스템을 사용합니다.Linkq.Dynamic;

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

  Type t = DynamicExpression.CreateClass(props);

나머지는 그냥 시스템을 사용하는 것입니다.반사.

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

@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

동적 클래스를 만들려는 사용자는 속성(예: 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를 참조해야 합니다.코드 분석.CSSharp 라이브러리.

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

작업을 수행할 수 있는 동적 모듈 및 클래스를 사용할 수 있습니다.유일한 단점은 앱 도메인에 로드된 상태로 남아 있다는 것입니다.하지만 의 버전으로.사용 중인 NET 프레임워크는 변경될 수 있습니다.NET 4.0은 수집 가능한 동적 어셈블리를 지원하므로 클래스/유형을 동적으로 재생성할 수 있습니다.

와! 답변 감사합니다!저는 당신과 공유하는 "데이터 테이블 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

그리고 "compile result type" 하위 항목에서 다음과 같이 변경했습니다.

    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

CSSharpProvider를 사용할 수 있습니다.

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

시스템을 사용할 수 있습니다.런타임.원격.대리인.진짜 프록시.그것은 당신이 낮은 수준의 어셈블리 유형의 것이 아닌 "일반적인" 코드를 사용할 수 있게 해줄 것입니다.

좋은 예는 이 질문에 대한 RealProxy 답변을 참조하십시오.

C#에서 메서드 호출을 가로채려면 어떻게 해야 합니까?

여기에 세 가지 질문이 있습니다.

다음과 같은 클래스를 만들고 싶습니다.이것을 할 수 있는 방법이 있습니까?

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

예, 이것은 가능하지만 그 목적은 클래스를 어떤 것처럼 보이게 하는 것이 아니라 이렇게 일하고, 행동하고, 데이터를 유지하는 것이어야 합니다.그리고 이것은 다음을 사용하여 화이트아웃할 수 있습니다.CodeGeneration, "T4 Template,dynamic,ExpandoObject,CSharpProvider또는AnonymousObject.


나는 이것이 런타임에 생성되기를 원합니다.

class런타임에 생성되지 않으면 아무것도 하지 않습니다.instance물건.

그리고 만약 내가 이해한다면, 당신은 당신을 구하려고 노력하고 있습니다.Employee크 가 있 데 이 터 는 기의 List<Field>언바운드되고 당신이 생각할 수 있는 최선의 방법은 생성하는 것입니다.class제한되지 않은 데이터를 런타임에 동적으로 유지합니다.


동적 도면요소 작성

문제가 발생한 경우 생성을 시도할 수 있습니다.Employee로서Entity하기와 같이DynamicEntity속성을 a로 사용할 수 있는 경우Dictionary<string,object>따라서 새로운 속성/필드를 사용하지 않고 확장할 필요가 없습니다.class디자인은 직원들을 위한 2-3개의 분야에 국한되지 않습니다.

public class DynamicEntity
{
    public string Name {get;private set;}
    public Dictionary<string,object> Attributes;
    
    public DynamicEntity(string name)
    {
        Name = name;
        Attributes = new Dictionary<string,object>();
        Attributes.Add("LogicalName",name);
        Attributes.Add("Id",Guid.NewGuid());
    }
    
    public object this[string key]
    {
        get {
            return Attributes[key];
        }
        
        set{
            Attributes[key] = value;
        }
    }
    
    public void AddAttribute<T>(string attributeName,T data)
    {
        Attributes.Add(attributeName,data);
    }
    
    public void SetAttributeValue<T>(string attributeName,T data)
    {
        Attributes[attributeName] = data;
    }
    
    public T GetAttributeValue<T>(string attributeName)
    {
        return (T)Attributes[attributeName];
    }
}

사용하기 위해 런타임에 개체를 만들고 속성을 읽고/쓰기/추가할 수 있습니다.

    var u = new DynamicEntity("employee"); //new object
    
    u.AddAttribute<int>("EmployeeID",10); //Add Id
    u["EmployeeName"]= "vinod"; //Add Name
    u["Designation"] = "hacker"; //Add Designation
    
    u.AddAttribute<string>("Address","India"); //Add New Attribute 
    
    u.SetAttributeValue<string>("EmployeeName","Vinod Srivastav");
    
    var id = u.GetAttributeValue<int>("EmployeeID"); //Read Attribute

모든 것이 잘되면 다음과 같은 개체를 얻을 수 있습니다.

여기에 이미지 설명 입력

Runtime Code Generation with JVM and CLR 피터 세스토프트

이런 종류의 프로그래밍에 정말 관심이 있는 사람들을 위해 일합니다.

당신을 위한 제 팁은 만약 당신이 무언가를 선언한다면 문자열을 피하려고 노력하는 것입니다, 그래서 만약 당신이 클래스 필드가 있다면 클래스 시스템을 사용하는 것이 더 낫습니다.문자열보다 필드 유형을 저장할 유형입니다.그리고 새로운 클래스를 만드는 대신 최상의 솔루션을 위해 새로운 클래스를 만드는 대신 FileInfo로 만든 클래스를 사용하려고 합니다.

언급URL : https://stackoverflow.com/questions/3862226/how-to-dynamically-create-a-class

반응형