【问题标题】:Any way to use the C# compiler object (CSharpCodeProvider) to build "inline"?有什么方法可以使用 C# 编译器对象(CSharpCodeProvider)来构建“内联”?
【发布时间】:2016-03-31 19:47:10
【问题描述】:

我使用 CSharpCodeProvider 来构建动态 C#,效果很好。比表达式树稍微快一点,当然比表达式树和 IL 更容易维护......

我遇到了一个似乎无法正常工作的案例。

ConsoleApp1.exe 我的班级

然后我使用 CSharpCodeProvider 生成内存临时 DLL。说,像这样基本的东西:

void TestFunc(MyClass 输入) { }

这会产生编译器错误,因为 CSharpCodeProvider 没有对 MyClass 的引用。由于 MyClass 存在于 EXE 中,因此无法添加对编译器对象的引用。我收到一条错误消息,提示它找不到 ConsoleApp1 的元数据。

有没有办法让代码在 EXE 的上下文中存在?或者有什么方法可以使参考工作?我知道如果我将 MyClass 移动到 DLL 中然后将其添加为引用,它会起作用,但这对于我的班级的用户来说是不可接受的要求。

编辑:

所以,使用纯表达式树,我生成了这个方法:

.Lambda #Lambda1<System.Func`2[ConsoleApplication2.Source,ConsoleApplication2.Dest]>(ConsoleApplication2.Source $var1) {
    .New ConsoleApplication2.Dest(){
        S1 = .Call $var1.get_S1(),
        S2 = .Call $var1.get_S2(),
        I1 = .Call $var1.get_I1(),
        I2 = .Call $var1.get_I2(),
        S3 = .Call $var1.get_S3(),
        S4 = .Call $var1.get_S4(),
        S5 = .Call $var1.get_S5()
    }
}

编译为 lambda,调用 1M 次需要 ~285ms。

“编译器”方式,我生成这段代码:

namespace ConsoleApplication2
{
    public class TestClass
    {
        public static ConsoleApplication2.Dest TestFunc(ConsoleApplication2.Source source)
        {
            ConsoleApplication2.Dest d = new ConsoleApplication2.Dest();

            d.S1 = source.S1;
            d.S2 = source.S2;
            d.I1 = source.I1;
            d.I2 = source.I2;
            d.S3 = source.S3;
            d.S4 = source.S4;
            d.S5 = source.S5;

            return d;
        }
    }
}

然后我构建了一个类型化的 lambda:

    ParameterExpression p1 = Expression.Parameter(typeof(Source));
    var v = Expression.Lambda<Func<Source, Dest>>(Expression.Call(mi, p1), new ParameterExpression[] { p1 }).Compile();

当我调用 v(obj) 1M 次时,只需要 133ms 是纯表达式树时间的 1/2。

我只是犹豫要不要走这条路,因为要求类必须在 EXE 甚至 DLL 中是公共的。

知道为什么表达式树这么慢吗?

【问题讨论】:

  • 听起来你有一个先有鸡还是先有蛋的问题——你在可执行文件中构建动态 DLL,但动态 DLL 需要引用可执行文件才能编译。如果是这样,答案是将 MyClass 移动到控制台应用程序和动态 DLL 都引用的类库。或者回到使用表达式树:)
  • 你能给我们看一些代码吗?具体来说 MyClass 定义/编译成什么?将可执行文件作为参考程序集应该没有问题。
  • @DStanley - 嗯......我的错......显然你可以添加一个EXE作为参考,但你必须专门将.EXE附加到程序集名称。此外,类型必须在 EXE 中公开。这样就解决了这部分问题,但并没有增加太多性能。
  • @mikez 是的,我确实让它工作了......虽然很奇怪......我将代表包裹在表达式 lambda 中,我的工作台是 133 毫秒,使用纯表达式树是 288 毫秒.不知道为什么纯表达式树需要更长的时间......
  • 您担心 1M 呼叫需要额外的 150 毫秒吗?这对应用程序的整体性能是否重要?

标签: c# .net compiler-construction


【解决方案1】:

有没有办法让代码在 EXE 的上下文中存在?

没有。 CSharpCodeProvider运行时创建一个程序集,因此无法将其“注入”到当前正在运行的程序集中,该程序集此时是一个已编译的程序集。

有什么方法可以使参考工作正常吗?

您自己回答了这个问题 - 将 EXE 扩展名添加到引用名称,以便它知道加载 EXE 而不是 DLL。

【讨论】:

    猜你喜欢
    • 2018-10-18
    • 1970-01-01
    • 2023-04-05
    • 2021-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多