【问题标题】:How to pass a generic list to a dynamically compiled C# code?如何将通用列表传递给动态编译的 C# 代码?
【发布时间】:2013-08-02 23:54:59
【问题描述】:

我想让用户将一段代码写成文本,即时编译,在我从数据源获取的集合上执行并得到结果。

我一直想将通用列表作为参数传递给动态编译的代码,但我想不出办法。以下是我的代码:

//User writes this code in a textbox and executes
var executeCode = @"//this line doesn't work because I don't know the type
                            MessageBox.Show(Parameters[0].Count());
                            //following works fine
                            var t = new List<string>{""asd"", ""xyz""};
                            var a = t.Select(x => x).First();
                            MessageBox.Show(a); 
                            return (object) a;";

#region template Code
executeCode = @"
                using System;
                using System.IO;
                using System.Windows.Forms;
                using System.Linq;
                using System.Collections.Generic;

                namespace MyNamespace {
                public class MyClass {

                public object DynamicCode(params object[] Parameters) {
                " + executeCode +
                "}   }    }";
#endregion template Code

var references = new[] { "System.dll", "System.Core.dll", "System.Windows.Forms.dll" };

var compilerParams = new CompilerParameters
            {
                GenerateInMemory = true,
                TreatWarningsAsErrors = false,
                GenerateExecutable = false,
                CompilerOptions = "/optimize"
            };
        compilerParams.ReferencedAssemblies.AddRange(references);

        var provider = new CSharpCodeProvider();
        var compile = provider.CompileAssemblyFromSource(compilerParams, executeCode);

        if (compile.Errors.HasErrors)
        {
            var text = compile.Errors.Cast<CompilerError>()
                              .Aggregate("Compile Error: ", (current, ce) => current + ("rn" + ce.ToString()));
            throw new Exception(text);
        }

        // execute the compiled code

        var assembly = compile.CompiledAssembly;
        var myObject = assembly.CreateInstance("MyNamespace.MyClass");
        if (myObject == null)
        {
            MessageBox.Show("Couldn't load class.");
            return;
        }

        var sampleList = new List<string> { "abcd", "bcd" };
        var codeParams = new object[] { sampleList };

        try
        {
            var loResult = myObject.GetType().InvokeMember("DynamicCode",BindingFlags.InvokeMethod, null, myObject, codeParams);
            MessageBox.Show("Method Call Result:\r\n\r\n" + loResult, "Compiler Demo", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
        catch (Exception loError)
        {
            MessageBox.Show(loError.Message, "Compiler Demo", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

在上面的代码中,我只是传递了一个字符串列表。但我会用一个对象来代替它。用户将编写 Linq 查询来过滤集合,我即时编译并返回结果。

对此的任何指示都会非常有帮助。 (我使用 C# 4.5)

【问题讨论】:

  • 你真的必须以这种难以管理的方式制作代码吗?有一种东西叫interface,它是几十年前发明的。
  • @sza 这是我的临时代码。如果它符合目的,我将修复可管理性部分......否则为什么要编写更多代码?
  • 你正在尝试调用.Count(),这样你就可以立即向下转换为IEnumerable&lt;object&gt; - 不管实际课程是什么。
  • 这将解决 Count() 但是如果我想编写一个 lambda 表达式来过滤列表基于说 Firstname 以 A 开头?在那种情况下,我将需要该类型,还是应该使用反射来获取 IEnumerable 的属性,然后执行 lamda 表达式?

标签: c#


【解决方案1】:

有多种选择。

  1. 将参数对象的类型更改为List&lt;string&gt;[]。如果您始终知道自己传递的是 List&lt;string&gt;,那么这就是要走的路。

  2. 在您的动态生成代码中输入:((List&lt;string)Parameters[0]).Count; 这有点笨拙,但会消除错误。

  3. 将参数对象的类型更改为dynamic。由于您是在运行时编译代码,因此编译时类型检查可能不是您的优先事项。

【讨论】:

  • 我使用了解决方案 1。我知道我传递给方法的类型,所以我总是将参数转换为特定类型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-04-07
  • 2014-12-13
  • 2018-03-30
  • 2014-04-30
  • 2015-10-19
  • 2011-06-10
  • 2012-08-21
相关资源
最近更新 更多