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

如何从存储过程返回的类定义字符串动态生成C#类/Type?

从类定义字符串动态生成Type的实现方案

当然可以做到!在C#中,我们可以通过动态编译技术把类定义字符串转换成可直接使用的Type对象,下面给你两种实用的实现方式,分别适配不同的.NET环境:

方案一:使用CSharpCodeProvider(适用于.NET Framework)

这是.NET Framework时代常用的动态编译方式,不需要额外安装NuGet包,直接用系统自带的类库:

using System;
using System.CodeDom.Compiler;
using System.Reflection;
using Microsoft.CSharp;

public static Type GenerateType(string classDefinition)
{
    // 补全必要的代码结构:添加using和命名空间,避免编译错误
    var fullCode = $@"
using System;
namespace DynamicTypes
{{
    {classDefinition}
}}";

    // 设置编译参数
    var compilerParams = new CompilerParameters
    {
        GenerateInMemory = true, // 在内存中生成程序集,不写入磁盘
        ReferencedAssemblies = { "System.dll" } // 引用必要的程序集
    };

    // 创建C#编译器
    using var provider = new CSharpCodeProvider();
    var compileResult = provider.CompileAssemblyFromSource(compilerParams, fullCode);

    // 检查编译错误
    if (compileResult.Errors.HasErrors)
    {
        var errorMsg = string.Join(Environment.NewLine, 
            compileResult.Errors.Cast<CompilerError>().Select(e => $"Error: {e.ErrorText}"));
        throw new InvalidOperationException($"编译失败:{errorMsg}");
    }

    // 从生成的程序集中获取Type(注意类名要和传入的定义一致)
    var assembly = compileResult.CompiledAssembly;
    return assembly.GetType($"DynamicTypes.{GetClassName(classDefinition)}");
}

// 辅助方法:从类定义字符串中提取类名
private static string GetClassName(string classDefinition)
{
    // 简单的提取逻辑,你可以根据实际情况优化(比如处理public、partial等修饰符)
    var startIndex = classDefinition.IndexOf("class ") + 6;
    var endIndex = classDefinition.IndexOf(" ", startIndex);
    if (endIndex == -1) endIndex = classDefinition.IndexOf("{", startIndex);
    return classDefinition.Substring(startIndex, endIndex - startIndex).Trim();
}

使用示例:

var classStr = "public class TableName { public int Column1 { get; set; } }";
Type dynamicType = GenerateType(classStr);

// 后续可以用反射创建实例、访问属性
object instance = Activator.CreateInstance(dynamicType);
PropertyInfo column1Prop = dynamicType.GetProperty("Column1");
column1Prop.SetValue(instance, 123);
Console.WriteLine(column1Prop.GetValue(instance)); // 输出123

方案二:使用Roslyn API(推荐,适用于.NET Core/.NET 5+)

Roslyn是微软官方的.NET编译器平台,功能更强大、性能更好,需要先安装NuGet包Microsoft.CodeAnalysis.CSharp:

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

public static Type GenerateTypeWithRoslyn(string classDefinition)
{
    // 补全完整代码结构
    var fullCode = $@"
using System;
namespace DynamicTypes
{{
    {classDefinition}
}}";

    // 构建语法树
    var syntaxTree = CSharpSyntaxTree.ParseText(fullCode);

    // 设置编译选项:引用必要的程序集
    var references = new MetadataReference[]
    {
        MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
        MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location)
    };

    var compilation = CSharpCompilation.Create(
        "DynamicAssembly",
        syntaxTrees: new[] { syntaxTree },
        references: references,
        options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

    // 编译到内存流
    using var ms = new System.IO.MemoryStream();
    var result = compilation.Emit(ms);

    // 检查编译错误
    if (!result.Success)
    {
        var errors = result.Diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error);
        var errorMsg = string.Join(Environment.NewLine, errors.Select(d => $"Error: {d.GetMessage()}"));
        throw new InvalidOperationException($"编译失败:{errorMsg}");
    }

    // 加载程序集并获取Type
    ms.Seek(0, System.IO.SeekOrigin.Begin);
    var assembly = Assembly.Load(ms.ToArray());
    return assembly.GetType($"DynamicTypes.{GetClassName(classDefinition)}");
}

// 复用之前的GetClassName辅助方法
private static string GetClassName(string classDefinition)
{
    var startIndex = classDefinition.IndexOf("class ") + 6;
    var endIndex = classDefinition.IndexOf(" ", startIndex);
    if (endIndex == -1) endIndex = classDefinition.IndexOf("{", startIndex);
    return classDefinition.Substring(startIndex, endIndex - startIndex).Trim();
}

注意事项

  • 类定义字符串要保证语法正确,否则编译会失败,建议添加必要的错误处理逻辑。
  • 如果你的类需要引用其他程序集(比如System.ComponentModel等),要在编译参数中添加对应的引用。
  • 生成的Type可以通过反射进行所有常规操作:创建实例、调用方法、访问属性等。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 06:52:40