Как я могу использовать CodeDOM для создания и загрузки сборки в AppDomain? - PullRequest
4 голосов
/ 18 августа 2010

Я работаю над проектом, который будет использовать CodeDOM для создания класса, который оценивает пользовательское выражение, создает сборку для класса и загружает сборку.Поскольку может быть довольно много пользовательских выражений, я хотел бы сначала создать домен приложения, выполнить создание / загрузку и выполнение CodeDOM для сборки в этом домене приложения, а затем выгрузить домен приложения.

IЯ немного искал и нашел много примеров того, как загрузить существующую сборку в домен приложений, но я не могу найти тот, который показывает мне, как создать сборку из внутри домена приложений.

В этом примере ( DynamicCode ) создается сборка с использованием CodeDOM, а затем загружается ее в домен приложений, однако автор генерирует сборку на диск.Я бы предпочел сгенерировать сборку в памяти, чтобы мне не приходилось управлять очисткой сгенерированных сборок.(хотя при этом создается папка .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;
}

Я считаю, что эти фрагменты кода показывают основные функциональные возможности моего проекта.Теперь все, что мне нужно сделать, это обернуть его в свой собственный домен приложений.

Ответы [ 4 ]

3 голосов
/ 18 августа 2010

Проблемы с курицей и яйцом. Вам нужна небольшая сборка загрузчика, которую вы можете загрузить в новый домен приложений. С хорошо известным классом, который загружает сгенерированную сборку CodeDom и запускает ее.

Делать это с GenerateInMemory довольно бессмысленно, вам придется сериализовать это в новый домен приложений. Это всего лишь куча накладных расходов, может с таким же успехом загрузить его с диска, он все равно есть. И это уже в памяти. Кэш-память файловой системы. Загрузка будет очень быстрой, поскольку на самом деле ее не нужно считывать с диска.

2 голосов
/ 20 августа 2010

Я нашел ответ, который искал на http://www.softwareinteractions.com/blog/2010/2/7/loading-and-unloading-net-assemblies.html. У него есть хорошая статья, подробно описывающая создание AppDomain и загрузку сборки в качестве плагина.Я последовал его примеру и смог создать AppDomain, создать прокси для моей фабрики классов ExpressionEvaluator, успешно вызвать его и получить результаты.

1 голос
/ 18 августа 2010

Просто используйте AssemblyBuilderAccess.Run при определении динамической сборки http://msdn.microsoft.com/en-us/library/system.reflection.emit.assemblybuilderaccess.aspx

Динамическая сборка может быть выполнена, но не сохранена.

0 голосов
/ 07 октября 2012

Откуда взялся метод CompilCode во всем этом? Кажется, это самая важная часть. И вы решили оставить это?

...