6

CodeDOM を使用して、ユーザー定義の式を評価し、クラスのアセンブリを作成し、アセンブリを読み込むクラスを作成するプロジェクトに取り組んでいます。かなりの数のユーザー定義式が存在する可能性があるため、最初に AppDomain を作成し、その AppDomain 内のアセンブリに対して CodeDOM の作成/読み込みと実行を実行してから、AppDomain をアンロードします。

かなり検索したところ、既存のアセンブリを AppDomain に読み込む方法の例がたくさん見つかりましたが、AppDomainからアセンブリを作成する方法を示す例が見つからないようです。

この例 ( DynamicCode ) は CodeDOM を使用してアセンブリを作成し、それを AppDomain に読み込みますが、作成者はアセンブリをディスクに生成しています。生成されたアセンブリのクリーンアップを管理する必要がないように、アセンブリをメモリ内に生成することをお勧めします。(ただし、一時フォルダーに .dll が作成されます)。

誰かがこれを行う方法の例を教えてもらえますか?

どんな助けでも大歓迎です。

私のコードからの抜粋をいくつか含めました。

private string CreateSource()
{
    CodeCompileUnit codeUnit = new CodeCompileUnit();
    CodeNamespace codeNamespace = new CodeNamespace(Namespace);
    CodeTypeDeclaration codeClass = new CodeTypeDeclaration
    {
        Name = "ExpressionEvaluator",
        IsClass = true,
        TypeAttributes = TypeAttributes.Public | TypeAttributes.Sealed
    };

    codeNamespace.Types.Add(codeClass);
    codeUnit.Namespaces.Add(codeNamespace);

    AddMethods(codeClass);

    string result = GenerateSourceCode(codeUnit);

    return result.ToString();
}

private CompilerResults CompileSource(string source)
{
    using (CodeDomProvider provider = new CSharpCodeProvider())
    {
        CompilerParameters parameters = CreateCompilerParameters();
        CompilerResults result = CompileCode(provider, parameters, source);

        return result;
    }
}

private static CompilerParameters CreateCompilerParameters()
{
    CompilerParameters result = new CompilerParameters
    {
        CompilerOptions = "/target:library",
        GenerateExecutable = false,
        GenerateInMemory = true
    };

    result.ReferencedAssemblies.Add("System.dll");

    return result;
}

private object RunEvaluator(CompilerResults compilerResults)
{
    object result = null;
    Assembly assembly = compilerResults.CompiledAssembly;

    if (assembly != null)
    {
        string className = "ExpressionEvaluator";
        object instance = assembly.CreateInstance("Lab.ExpressionEvaluator");

        Module[] modules = assembly.GetModules(false);

        Type type = (from t in modules[0].GetTypes()
                     where t.Name == className
                     select t).FirstOrDefault();

        MethodInfo method = (from m in type.GetMethods()
                             where m.Name == "Evaluate"
                             select m).FirstOrDefault();

        result = method.Invoke(instance, null);
    }
    else
    {
        throw new Exception("Unable to load Evaluator assembly");
    }

    return result;
}

これらのコード スニペットは、私のプロジェクトの基本的な機能を示していると思います。あとは、それを独自の AppDomain にラップするだけです。

4

4 に答える 4

3

鶏が先か卵が先か。新しいAppDomainにロードできる小さなブートストラッパーアセンブリが必要です。CodeDomで生成されたアセンブリをロードして実行するよく知られたクラスを使用します。

GenerateInMemoryを使用してこれを行うことは非常に無意味であり、新しいAppDomainにシリアル化する必要があります。これは単なるオーバーヘッドの集まりであり、ディスクからロードすることもできますが、とにかくそこにあります。そして、それはすでにメモリにあります。ファイルシステムキャッシュのメモリ。実際にディスクから読み取る必要がないため、ロードは非常に高速になります。

于 2010-08-18T15:27:39.973 に答える
3

http://www.softwareinteractions.com/blog/2010/2/7/loading-and-unloading-net-assemblies.htmlで探していた答えを見つけました。彼は、AppDomain の作成とプラグインとしてのアセンブリの読み込みについて詳しく説明した素晴らしい記事を持っています。私は彼の例に従い、AppDomain を作成し、ExpressionEvaluator クラス ファクトリのプロキシを作成し、それを正常に呼び出して結果を受け取ることができました。

于 2010-08-19T21:38:35.340 に答える
1

動的アセンブリhttp://msdn.microsoft.com/en-us/library/system.reflection.emit.assemblybuilderaccess.aspxAssemblyBuilderAccess.Runを定義するときに使用するだけです

動的アセンブリは実行できますが、保存できません。

于 2010-08-18T14:13:00.710 に答える
0

CompilCodeこの方法はどこから来たのですか?それが最も重要な部分のように思えますが、それを省略することにしましたか?

于 2012-10-07T10:46:38.080 に答える