You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#中创建带动态字段与属性的动态类作为数据模型

在C#中创建带动态字段的数据模型类

下面提供三种实用方案,覆盖从快速实现到强类型生成的不同需求场景:

方案1:用ExpandoObject快速实现动态属性

适合简单场景,无需强类型,直接动态添加属性:

using System.Dynamic;

public dynamic CreateDynamicModel(params string[] fields)
{
    dynamic expando = new ExpandoObject();
    var expandoDict = (IDictionary<string, object>)expando;

    foreach (var field in fields)
    {
        if (!expandoDict.ContainsKey(field))
        {
            expandoDict[field] = null; // 初始值可按需修改为默认值
        }
    }

    return expando;
}

// 使用示例
var model = CreateDynamicModel("Name", "Age", "Email");
model.Name = "张三";
model.Age = 25;
Console.WriteLine(model.Name); // 输出:张三

注意:这种方式本质是字典包装,编译时无属性检查,适合快速验证或简单数据传递场景。

方案2:通过反射Emit生成强类型动态类

如果需要真正可复用的.NET类型(比如用于序列化、ORM映射),可以用反射在运行时生成类:

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

public static Type CreateDynamicClass(params string[] propertyNames)
{
    // 定义动态程序集和模块
    var assemblyName = new AssemblyName($"DynamicModels_{Guid.NewGuid()}");
    var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
    var moduleBuilder = assemblyBuilder.DefineDynamicModule("DynamicModule");

    // 定义类结构
    var typeBuilder = moduleBuilder.DefineType($"DynamicModel_{Guid.NewGuid()}", TypeAttributes.Public | TypeAttributes.Class);

    // 为每个字段生成属性
    foreach (var propName in propertyNames)
    {
        // 生成私有字段
        var fieldBuilder = typeBuilder.DefineField($"_{propName}", typeof(object), FieldAttributes.Private);

        // 生成属性的get方法
        var getMethod = typeBuilder.DefineMethod($"get_{propName}", MethodAttributes.Public | MethodAttributes.SpecialName, typeof(object), Type.EmptyTypes);
        var getIL = getMethod.GetILGenerator();
        getIL.Emit(OpCodes.Ldarg_0);
        getIL.Emit(OpCodes.Ldfld, fieldBuilder);
        getIL.Emit(OpCodes.Ret);

        // 生成属性的set方法
        var setMethod = typeBuilder.DefineMethod($"set_{propName}", MethodAttributes.Public | MethodAttributes.SpecialName, typeof(void), new[] { typeof(object) });
        var setIL = setMethod.GetILGenerator();
        setIL.Emit(OpCodes.Ldarg_0);
        setIL.Emit(OpCodes.Ldarg_1);
        setIL.Emit(OpCodes.Stfld, fieldBuilder);
        setIL.Emit(OpCodes.Ret);

        // 绑定get/set方法到属性
        var propBuilder = typeBuilder.DefineProperty(propName, PropertyAttributes.None, typeof(object), null);
        propBuilder.SetGetMethod(getMethod);
        propBuilder.SetSetMethod(setMethod);
    }

    // 生成并返回类型
    return typeBuilder.CreateType();
}

// 使用示例
var dynamicType = CreateDynamicClass("Id", "Title", "Content");
var instance = Activator.CreateInstance(dynamicType);

// 设置属性值
dynamicType.GetProperty("Title").SetValue(instance, "动态类示例");
// 获取属性值
var title = dynamicType.GetProperty("Title").GetValue(instance);
Console.WriteLine(title); // 输出:动态类示例

这种方式生成的是标准.NET类型,支持反射、序列化等所有常规操作,适合需要强类型模型的场景。

方案3:用Roslyn编译生成自定义类

如果需要更复杂的类定义(比如添加特性、实现接口),可以用Roslyn在运行时编译C#代码:

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System;
using System.IO;
using System.Linq;

public static Type CreateDynamicClassWithRoslyn(params string[] propertyNames)
{
    // 构造类的代码模板
    var properties = string.Join("\n        ", propertyNames.Select(name => 
        $"public object {name} {{ get; set; }}"));

    var code = $@"
namespace DynamicModels
{{
    public class GeneratedModel
    {{
        {properties}
    }}
}}";

    // 编译代码
    var syntaxTree = CSharpSyntaxTree.ParseText(code);
    var references = AppDomain.CurrentDomain.GetAssemblies()
        .Where(a => !a.IsDynamic && !string.IsNullOrEmpty(a.Location))
        .Select(a => MetadataReference.CreateFromFile(a.Location))
        .ToList();

    var compilation = CSharpCompilation.Create($"DynamicAssembly_{Guid.NewGuid()}")
        .WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary))
        .AddReferences(references)
        .AddSyntaxTrees(syntaxTree);

    using var ms = new MemoryStream();
    var result = compilation.Emit(ms);

    if (!result.Success)
    {
        var errors = result.Diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error);
        throw new InvalidOperationException($"编译失败:{string.Join("\n", errors.Select(e => e.GetMessage()))}");
    }

    ms.Seek(0, SeekOrigin.Begin);
    var assembly = Assembly.Load(ms.ToArray());
    return assembly.GetType("DynamicModels.GeneratedModel");
}

// 使用示例
var roslynType = CreateDynamicClassWithRoslyn("Name", "Address", "Phone");
var roslynInstance = Activator.CreateInstance(roslynType);
roslynType.GetProperty("Phone").SetValue(roslynInstance, "13800138000");
Console.WriteLine(roslynType.GetProperty("Phone").GetValue(roslynInstance)); // 输出:13800138000

需要先通过NuGet安装Microsoft.CodeAnalysis.CSharp包,这种方式灵活性极高,几乎支持所有C#类的语法特性。

内容的提问来源于stack exchange,提问作者user

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 20:24:32