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

如何在.NET中实现由用户输入动态创建函数体并调用?

Great question! For your internal tool where security isn't a concern, .NET has a couple of built-in, straightforward ways to let users input function implementations and compile them for later use. Let's dive into the most practical approaches:

1. CodeDOM (Built-in, No External Dependencies)

CodeDOM is .NET's classic dynamic compilation API—it's included out of the box in both .NET Framework and .NET Core/.NET 5+, making it perfect for your "no external dependencies" requirement. Here's how to implement it:

Step-by-Step Breakdown

  • Wrap user code in a valid class: You'll need to take the function header you provide, plus the user's implementation, and package it into a complete C# code snippet (including necessary using statements).
  • Compile in-memory: Use the CSharpCodeProvider to compile the code directly into memory (no disk writes needed).
  • Store a delegate: Once compiled, use reflection to grab the method and convert it to a delegate for easy, fast later calls.

Full Code Example

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

public class DynamicFunctionManager
{
    // Store the compiled function as a delegate for quick invocation
    public Delegate CompiledFunction { get; private set; }

    public bool CompileFunction(string functionHeader, string userImplementation, Type[] parameterTypes, Type returnType)
    {
        // Build the full code template—add user-specified using statements here if needed
        string fullCode = $@"
using System;
// Let users add extra using lines here (e.g., using System.Linq;)
public class DynamicFunctionContainer
{{
    {functionHeader}
    {{
        {userImplementation}
    }}
}}";

        // Configure compilation settings
        var compilerParams = new CompilerParameters
        {
            GenerateInMemory = true, // Keep the assembly in memory—no files created
            TreatWarningsAsErrors = false,
            ReferencedAssemblies = { "System.dll", "System.Core.dll" } // Add other framework assemblies if required
        };

        // Compile the code
        using var codeProvider = new CSharpCodeProvider();
        CompilerResults compileResults = codeProvider.CompileAssemblyFromSource(compilerParams, fullCode);

        // Handle compilation errors (useful for giving feedback to the user)
        if (compileResults.Errors.HasErrors)
        {
            foreach (CompilerError error in compileResults.Errors)
            {
                Console.WriteLine($"Compilation Error: {error.ErrorText} (Line {error.Line})");
            }
            return false;
        }

        // Load the compiled assembly and grab the method
        Assembly compiledAssembly = compileResults.CompiledAssembly;
        Type functionClass = compiledAssembly.GetType("DynamicFunctionContainer");
        MethodInfo targetMethod = functionClass.GetMethod(GetMethodNameFromHeader(functionHeader));

        // Create a delegate for fast future calls
        Type delegateType = typeof(Func<,>).MakeGenericType(parameterTypes.Append(returnType).ToArray());
        CompiledFunction = Delegate.CreateDelegate(delegateType, targetMethod);

        return true;
    }

    // Helper to extract the method name from the function header (e.g., "Add" from "public static int Add(int a, int b)")
    private string GetMethodNameFromHeader(string header)
    {
        return header.Split(new[] {' ', '('}, StringSplitOptions.RemoveEmptyEntries)[2];
    }

    // Invoke the compiled function with parameters
    public object InvokeFunction(params object[] parameters)
    {
        return CompiledFunction.DynamicInvoke(parameters);
    }
}

How to Use It

// Example: Let's compile a simple addition function
var functionManager = new DynamicFunctionManager();
bool compileSuccess = functionManager.CompileFunction(
    functionHeader: "public static int Add(int firstNum, int secondNum)",
    userImplementation: "return firstNum + secondNum;",
    parameterTypes: new Type[] { typeof(int), typeof(int) },
    returnType: typeof(int));

if (compileSuccess)
{
    int result = (int)functionManager.InvokeFunction(2, 5);
    Console.WriteLine($"Result: {result}"); // Outputs 7
}
2. Roslyn (Modern Alternative, Requires NuGet)

If you're open to adding a NuGet package (Microsoft.CodeAnalysis.CSharp), Roslyn is a more powerful, flexible option. It's .NET's official compiler platform and offers better error diagnostics and syntax tree manipulation. However, since you specified no external dependencies, this is just a useful alternative to keep in mind if your requirements change later.

Key Tips for Your Tool
  • Let users add using statements: Add a text box where users can input additional using lines, then insert them into the code template—this lets them use any .NET framework types they need.
  • Store multiple functions: Use a Dictionary<string, Delegate> to store compiled functions by name or ID, so you can call different ones later.
  • Error feedback: Show compilation errors to the user so they can fix their implementation code.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 08:42:48