3

一部のデータに対して条件付きステートメントを設計するためのグラフィカルな形式をユーザーに提供したいと考えています。私たちのアプリケーションは、そのグラフィカルな形式を取り、それを C# に変換してコンパイルし、いくつかのデータに対して条件ステートメントを実行して、ブール値を返します。

問題は、ユーザーが新しい条件ステートメントを作成するたびにアプリケーションを再構築する必要がないため、実行時にこれらの条件ステートメントを作成してコンパイルする (そしてもちろん実行する) 必要があることです。

LINQ 式ツリーを使用することも考えましたが、コンパイルされた LINQ 式ツリーは保存できないため、条件ステートメントを実行するたびに再コンパイルする必要があります。

別の方法としては、CodeDOM を使用して条件文を .dll としてコンパイルすることをお勧めします (これらは、条件文に対して実行するデータをパラメーターとして受け取る静的クラスの静的メソッドに変換されます)。これにより、コンパイルされたステートメントを保存でき、実行時に .dll をロードおよびアンロードできます。また、LINQ 式ツリーよりも C# の if ステートメントを生成する方が簡単です。

または、Roslyn を使用して .dll を生成することもできます。これは CodeDOM よりも高速であると報告されていますが、Roslyn はまだ CTP にあります。

知っておくべき隠れた落とし穴、またはこれを行うための一般的なパターンはありますか? データに対してテストする関数のみを生成するように細心の注意を払う (そして、データを変更したり、他の関数の呼び出しを許可したりしない) こと以外に、他に注意すべきことは何ですか? これらの .dll のロードとアンロード (場合によっては数百) によって問題が発生しますか? 各 .dll に独自の名前空間が与えられている場合、(数百の可能性がある) .dll をロードおよびアンロードするとアーティファクトが残りますか?

4

3 に答える 3

3

条件文が実行されるたびに再コンパイルする必要があります

これは問題になるとは思いません。1 秒間に多くの式をコンパイルする必要がない限り、式ツリーのコンパイルによるパフォーマンスへの影響は顕著ではありません。

実行時に .dll をロードおよびアンロードできます

あまり。.Net で通常のアセンブリをアンロードすることはできません。収集可能なアセンブリは、使用されていないことが検出されるとアンロードされますが、これは動的アセンブリ (ディスクからロードされたものではない) に対してのみ機能します。AppDomain をアンロードすることもできます。これにより、そのドメインにロードされたすべてのアセンブリもアンロードされますが、これは別の AppDomain でステートメントを実行することを意味します。

また、LINQ 式ツリーよりも C# の if ステートメントを生成する方が簡単です。

それは本当に問題ですか?そのコードは 1 回だけ記述します。if ステートメントを作成することは、その方法を知っていれば、実際には式ツリーでそれほど難しくないと思います。特に、コード生成に使用すると非常に冗長な Roslyn と比較すると (主なユース ケースではないため)。

[Roslyn] は CodeDOM よりも高速であると報告されていますが、Roslyn はまだ CTP にあります。

そのソースを引用していただけますか?しかし、コンパイルの速度が実際に重要であるとは思えません。

各 .dll に独自の名前空間が与えられている場合…</p>

DLL には名前空間がありません。実際、CLR は実際には名前空間を処理しません。名前にドットが含まれるクラスを認識するだけです。

于 2013-04-22T22:37:17.473 に答える
0

いくつかの追加メモ(@ svick -sの回答で、ほとんどの場合2番目)、別の角度...

  1. 可能であれば、Roslynを使用することをお勧めします-ターゲットに応じて. 必要なもののための次世代ツールと、市販されている真の「コンパイラサービス」を手に入れることができます:)、しかし真剣に。

  2. 構築する広範な式ツリーがない場合(つまり、限定されたセット) は、2 番目のオプションとしてそれをお勧めします。「通信」するのが面倒なAppDomain経由でない限り、CodeDomでdll-sをアンロードすることはできません(基本的にクロスプロセス)。

  3. 実行する「任意の」ユーザー コードがさらにある場合、または C# を使用した完全な「ファイル」がある場合は、C# をほとんど模倣する必要があることを意味します。それから CodeDom を使用します。CodeDOM は堅固で機能しますが、私はこの順序で進みます。

于 2013-04-22T23:01:34.497 に答える
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 に答える