0

クラスのフィールド名を事前に知らなくても、実行時に動的クラスを作成できますか?

たとえば、ユーザーが文字列のリストを入力できるようにし、ユーザーがリストを送信すると、フィールドの名前を文字列のリストとして持つクラスを作成します。

たとえば、次のようになります。

List<string> TempList = new List<string>() { "Name1", "Name2" };

このように実行時にクラスを作成できますか?

public class CustomClass(){
    public string Name1;
    public string Name2;
}
4

2 に答える 2

0

必要に応じて、Reflection.Emit を使用して実行時にクラスを作成できます。考えられる方法の 1 つは、次の手順を実行することです。

このクラスを使用して、プロセス全体を実行します。プロパティに必要な適切なタイプでタイプ T を閉じます。あなたの場合、タイプ文字列を使用します。

class ClassFromList<T>
{
    public object Instance { get; set; }

    public ClassFromList(List<string> list)
    {
        var type = new DynamicClass().Builder;

        list.ForEach(item => new DynamicProperty<T>(type, item));

        Instance = Activator.CreateInstance(type.CreateType());
    }
}

上記のクラス内で、これはタイプ TypeBuilder のプロパティを提供するため、実行時にクラスを作成できます。

class DynamicClass
{
    public TypeBuilder Builder { get; set; }

    public DynamicClass()
    { 
        var name = new AssemblyName("DynamicAssembly");
        var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run);
        var module = assembly.DefineDynamicModule("DynamicModule");

        Builder = module.DefineType("DynamicClass", TypeAttributes.Public);
    }
}

一方、次のクラスは、クラスに実装させたいプロパティを作成します。

class DynamicProperty<T>
{
    public DynamicProperty(TypeBuilder builder, string name)
    {
        var field = builder.DefineField("_" + name, typeof(T), FieldAttributes.Private);
        var property = builder.DefineProperty(name, PropertyAttributes.None, typeof(T), new Type[0]);
        var getter = builder.DefineMethod("get_" + name, MethodAttributes.Public | MethodAttributes.SpecialName, typeof(T), new Type[0]);
        var setter = builder.DefineMethod("set_" + name, MethodAttributes.Public | MethodAttributes.SpecialName, null, new Type[] { typeof(T) });

        var getGenerator = getter.GetILGenerator();
        var setGenerator = setter.GetILGenerator();

        getGenerator.Emit(OpCodes.Ldarg_0);
        getGenerator.Emit(OpCodes.Ldfld, field);
        getGenerator.Emit(OpCodes.Ret);

        setGenerator.Emit(OpCodes.Ldarg_0);
        setGenerator.Emit(OpCodes.Ldarg_1);
        setGenerator.Emit(OpCodes.Stfld, field);
        setGenerator.Emit(OpCodes.Ret);

        property.SetGetMethod(getter);
        property.SetSetMethod(setter);
    }
}

あとはプロセス全体をテストするだけです。次のコードは、文字列型の「a」、「b」、「c」という名前の 3 つのプロパティを作成し、それらに値「value1」、「value2」、「value3」をそれぞれ追加し、新しいクラスのインスタンスを作成し、すべてを表示します。プロパティ、そのタイプ、および値をあなたに。

class Program
{
    static void Main()
    {
        var list = new List<string>() { "a", "b", "c" };

        var instance = new ClassFromList<string>(list).Instance;

        instance.GetType().GetProperty("a").SetValue(instance, "value1", null);
        instance.GetType().GetProperty("b").SetValue(instance, "value2", null);
        instance.GetType().GetProperty("c").SetValue(instance, "value3", null);

        instance.GetType()
                .GetProperties()
                .ToList()
                .ForEach(x => Console.WriteLine(x.Name + " " + x.PropertyType + " " + x.GetValue(instance, null)));

        Console.Read();
    }
}

編集:クラスに実際にフィールドが必要な場合は、今気付いたように、次の DynamicProperty クラスの代わりに DynamicField クラスを使用する必要があります。ただし、オブジェクト間のデータ転送では、フィールドよりもプロパティが優先されることに注意してください。

class DynamicField<T>
{
    public DynamicField(TypeBuilder builder, string name)
    {
        var field = builder.DefineField(name, typeof(T), FieldAttributes.Public);
    }
}
于 2013-06-15T04:24:47.577 に答える
0

これを行うには、次を使用する必要があります。

DynamicObject クラス

それを使用する方法のリンクがあります: DynamicObject Class

于 2013-06-14T13:41:50.240 に答える