有没有办法使用C#编译器对象(CSharpCodeProvider)来构建“内联”?

时间:2016-03-31 19:47:11

标签: c# .net compiler-construction

我使用CSharpCodeProvider来构建动态C#,它运行良好。比表达式树快一点,当然更容易维护表达式树和IL ...

我遇到的情况似乎不会起作用。

ConsoleApp1.exe   MyClass的

然后我使用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中,我只是对这条路线犹豫不决。

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

1 个答案:

答案 0 :(得分:0)

  

有没有在EXE的上下文中使代码生效?

没有。 CSharpCodeProvider运行时创建一个程序集,因此无法注入&#34;注入&#34;进入当前运行的程序集,这是一个在那时编译的程序集。

  

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

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