3

我们想给用户一个图形格式来设计一些数据的条件语句。我们的应用程序将采用该图形格式,将其转换为 C#,对其进行编译,然后针对某些数据运行条件语句,并返回一个布尔值。

问题是这些条件语句需要在运行时编写和编译(当然,执行),因为我们不会在每次用户创建新的条件语句时重新构建应用程序。

我们考虑过使用 LINQ 表达式树,但编译后的 LINQ 表达式树无法保存,这意味着每次执行条件语句时都需要重新编译。

我们认为更好的替代方法是使用 CodeDOM 将条件语句编译为 .dll(它们将被转换为静态类的静态方法,该静态类将数据作为参数,针对条件语句运行)。这允许我们保存编译后的语句,并且我们可以在运行时加载和卸载 .dll。此外,生成 C# if 语句比生成 LINQ 表达式树更容易。

或者,我们可以使用 Roslyn 生成 .dll。据报道,这比 CodeDOM 快,但 Roslyn 仍在 CTP 中。

是否存在我们应该知道的隐藏陷阱或执行此操作的一般模式?除了非常小心地只生成对数据进行测试的函数(并且不修改数据或允许调用任何其他函数)之外,我们还应该注意什么?加载和卸载(可能数百个)这些 .dll 会导致问题吗?如果每个 .dll 都有自己独特的命名空间,加载和卸载(可能有数百个)它们会留下工件吗?

4

3 回答 3

3

每次要执行条件语句时,我们都需要重新编译

我不认为这会是个问题。除非您需要每秒编译许多表达式,否则编译表达式树对性能的影响应该不会很明显。

我们可以在运行时加载和卸载 .dll

并不真地。您无法在 .Net 中卸载普通程序集。一旦检测到未使用可收集程序集,它将被卸载,但这仅适用于动态程序集(不是从磁盘加载的程序集)。您还可以卸载 AppDomain,这也会卸载加载到该域中的所有程序集,但这意味着在单独的 AppDomain 中运行您的语句。

此外,生成 C# if 语句比生成 LINQ 表达式树更容易。

这真的很重要吗?您只需要编写一次该代码。而且我不认为使用表达式树创建 if 语句实际上要困难得多,只要你知道如何去做。尤其是与 Roslyn 相比,后者在用于代码生成时非常冗长(因为这不是它的主要用例)。

据报道,[Roslyn] 比 CodeDOM 快,但 Roslyn 仍在 CTP 中。

你能引用一个来源吗?但我真的怀疑编译速度对你来说真的很重要。

如果每个 .dll 都有自己唯一的命名空间……</p>

这没有任何意义,DLL 没有命名空间。事实上,CLR 并不真正处理名称空间,它只是看到一个名称中有点的类。

于 2013-04-22T22:37:17.473 回答
0

完成这件事绝非易事,但您可能需要考虑通过自己发出 IL 来动态地在内存中创建程序集。

这方面的例子可以在这里找到。你会做这样的事情:

AppDomain domain = Thread.GetDomain();
// create a new assembly for the proxy
AssemblyBuilder assemblyBuilder = 
    domain.DefineDynamicAssembly(
        new AssemblyName("ProxyAssembly"), 
            AssemblyBuilderAccess.Run);

// create a new module for the proxy
ModuleBuilder moduleBuilder = 
    assemblyBuilder.DefineDynamicModule("ProxyModule", true);

// Set the class to be public and sealed
TypeAttributes typeAttributes = 
    TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed;

// Construct the type builder
TypeBuilder typeBuilder = 
    moduleBuilder.DefineType(typeof(TInterface).Name 
    + "Proxy", typeAttributes, channelType);

List<Type> allInterfaces = new List<Type>(typeof(TInterface).GetInterfaces());
allInterfaces.Add(typeof(TInterface));

//add the interface
typeBuilder.AddInterfaceImplementation(typeof(TInterface));

//construct the constructor
Type[] ctorArgTypes = new Type[] { ctorArgType };
CreateConstructor(channelType, typeBuilder, ctorArgTypes);

//...

//construct the method builders from the method infos defined in the interface
List<MethodInfo> methods = GetAllMethods(allInterfaces);
foreach (MethodInfo methodInfo in methods)
{
    MethodBuilder methodBuilder = 
        ConstructMethod(channelType, methodInfo, typeBuilder, 
            ldindOpCodeTypeMap, stindOpCodeTypeMap);
    typeBuilder.DefineMethodOverride(methodBuilder, methodInfo);
}

//create the type and construct an instance
Type t = typeBuilder.CreateType();
TInterface instance = 
    (TInterface)t.GetConstructor(ctorArgTypes).Invoke(
        new object[] { channelCtorValue });

return instance;

希望这可以帮助。

于 2013-04-23T00:16:04.137 回答
0

只是一些额外的注释(在@svick -s 的回答中,我大部分时间都排在第二位),不同的角度......

  1. 如果可以的话,我会说和罗斯林一起去——这取决于你的目标。您将获得满足您需要的下一代工具和市场上真正的“编译器服务”:),但要认真。

  2. 如果您没有要构建的广泛表达式树- 即有限集 - 我建议将其作为第二个选项。你不能用 CodeDom 卸载 dll-s,除非通过 AppDomain 来“沟通”(基本上是跨进程)。

  3. 如果您有更多“任意”用户代码要运行- 或使用 C# 的完整“文件” - 这意味着您必须非常模仿 C# - 然后使用 CodeDom。CodeDOM 是可靠的并且可以工作,但我会按照这个顺序进行。

于 2013-04-22T23:01:34.497 回答