Компилировать c # во время выполнения для формы окна [дубликат]

Попробуйте вот так:

const stateMap = (state) => {
    console.log('state', state);
    return {
        //something from state
    };
};

export default connect(stateMap)(App);
148
задан esac 5 May 2009 в 19:55
поделиться

6 ответов

Лучшим решением для C # / всех статических языков .NET является использование CodeDOM для таких вещей. (В качестве примечания, его другая основная цель заключается в динамическом построении битов кода или даже целых классов.)

Вот хороший пример из блога LukeH , который использует некоторые LINQ тоже просто для удовольствия.

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CSharp;
using System.CodeDom.Compiler;

class Program
{
    static void Main(string[] args)
    {
        var csc = new CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v3.5" } });
        var parameters = new CompilerParameters(new[] { "mscorlib.dll", "System.Core.dll" }, "foo.exe", true);
        parameters.GenerateExecutable = true;
        CompilerResults results = csc.CompileAssemblyFromSource(parameters,
        @"using System.Linq;
            class Program {
              public static void Main(string[] args) {
                var q = from i in Enumerable.Range(1,100)
                          where i % 2 == 0
                          select i;
              }
            }");
        results.Errors.Cast<CompilerError>().ToList().ForEach(error => Console.WriteLine(error.ErrorText));
    }
}

Класс первостепенной важности здесь - CSharpCodeProvider, который использует компилятор для компиляции кода «на лету». Если вы хотите запустить код, вам просто нужно использовать немного отражения для динамической загрузки сборки и ее выполнения.

Здесь - еще один пример на C #, который (хотя чуть менее кратким) дополнительно показывает вам, как запустить исполняемый код во время выполнения, используя пространство имен System.Reflection.

152
ответ дан Kamarey 25 August 2018 в 10:07
поделиться
  • 1
    Хотя я сомневаюсь, что вы используете Mono, я подумал, что, возможно, стоит указать, что существует пространство имен Mono.CSharp ( mono-project.com/CSharp_Compiler ), которое фактически содержит компилятор в качестве службы, так что вы может динамически запускать базовый код / ​​оценивать выражения inline с минимальными проблемами. – Noldorin 5 May 2009 в 20:16
  • 2
    что было бы реальным миром для этого. Я довольно зеленый при программировании в целом, и я думаю, что это круто, но я не могу думать о причине, по которой вы хотели бы / это было бы полезно. Спасибо, если вы объясните. – Crash893 7 May 2009 в 14:28
  • 3
    @ Crash893: система сценариев для практически любого приложения-дизайнера может хорошо использовать это. Конечно, есть альтернативы, такие как IronPython LUA, но это, безусловно, одно. Обратите внимание, что система плагинов будет лучше развита, выставляя интерфейсы и загружая скомпилированные библиотеки DLL, которые содержат их реализацию, а не загружают код напрямую. – Noldorin 7 May 2009 в 15:31
  • 4
    Я всегда думал о & quot; CodeDom & quot; как вещь, которая позволяет мне создать файл кода с использованием DOM - объектной модели документа. В System.CodeDom существуют объекты для представления всех артефактов, которые включает в себя код - объект для класса, для интерфейса, для конструктора, оператора, свойства, поля и т. Д. Затем я смогу построить код с использованием этой объектной модели. То, что показано здесь в этом ответе, - это компиляция файла кода в программе. Не CodeDom, хотя, как и CodeDom, он динамически создает сборку. Аналогия: я могу создать HTML-страницу, используя DOM, или используя конкатенты строк. – Cheeso 14 May 2009 в 22:49
  • 5
    вот статья SO, которая показывает CodeDom в действии: stackoverflow.com/questions/865052/… – Cheeso 14 May 2009 в 22:52

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

По крайней мере, я мог бы определить интерфейс, который им потребуется для реализации, тогда они предоставить раздел «код», который реализовал этот интерфейс.

У вас может быть проблема, если вы используете interface в качестве базового типа. Если вы добавите новый метод к interface в будущем, все существующие классы, поставляемые клиентом, которые реализуют interface, теперь станут абстрактными, что означает, что вы не сможете скомпилировать или создать экземпляр класса, поставляемого клиентом во время выполнения.

У меня возникла эта проблема, когда пришло время добавить новый метод примерно через год после отправки старого интерфейса и после распределения большого количества «старых» данных, которые необходимо было поддерживать. Я закончил создание нового интерфейса, унаследованного от старого, но этот подход усложнил загрузку и создание экземпляров классов, предоставленных клиентом, потому что мне пришлось проверить, какой интерфейс доступен.

Одно из решений, о которых я думал в то время было вместо этого использовать фактический класс как базовый тип, такой как тот, который приведен ниже. Сам класс может быть помечен как абстрактный, но все методы должны быть пустыми виртуальными методами (а не абстрактными методами). Клиенты могут затем переопределять методы, которые они хотят, и я могу добавить новые методы в базовый класс, не делая недействительным существующий код, поставляемый клиентом.

public abstract class BaseClass
{
    public virtual void Foo1() { }
    public virtual bool Foo2() { return false; }
    ...
}

Независимо от того, применяется ли эта проблема, вы должны подумать о том, как модифицировать интерфейс между вашей базой кода и кодом, поставляемым клиентом.

36
ответ дан Brian Ensink 25 August 2018 в 10:07
поделиться

Нашел это полезным - гарантирует, что скомпилированная сборка ссылается на все, на что вы ссылаетесь в данный момент, поскольку есть хороший шанс, что вы хотите, чтобы C #, который вы компилируете, использовал некоторые классы и т. д. в коде, который испускает это:

        var refs = AppDomain.CurrentDomain.GetAssemblies();
        var refFiles = refs.Where(a => !a.IsDynamic).Select(a => a.Location).ToArray();
        var cSharp = (new Microsoft.CSharp.CSharpCodeProvider()).CreateCompiler();
        var compileParams = new System.CodeDom.Compiler.CompilerParameters(refFiles);
        compileParams.GenerateInMemory = true;
        compileParams.GenerateExecutable = false;

        var compilerResult = cSharp.CompileAssemblyFromSource(compileParams, code);
        var asm = compilerResult.CompiledAssembly;

В моем случае я выбрал класс, имя которого было сохранено в строке, className, которая имела один открытый статический метод с именем Get(), который возвращался с типом StoryDataIds. Вот как выглядит этот метод:

        var tempType = asm.GetType(className);
        var ids = (StoryDataIds)tempType.GetMethod("Get").Invoke(null, null);
1
ответ дан Chris Moschini 25 August 2018 в 10:07
поделиться

Пространство имен System.CodeDom.Compiler должно помочь. См. в этой статье

1
ответ дан FryGuy 25 August 2018 в 10:07
поделиться

Для компиляции вы можете просто инициировать вызов оболочки для компилятора csc.

C # Примеры угловых оболочек

РЕДАКТИРОВАТЬ: Или еще лучше , используйте CodeDOM, как предложил Нолдорин ...

3
ответ дан Gary.Ray 25 August 2018 в 10:07
поделиться
  • 1
    Да, хорошая вещь с CodeDOM заключается в том, что она может генерировать сборку для вас в памяти (а также предоставлять сообщения об ошибках и другую информацию в легко читаемом формате). – Noldorin 5 May 2009 в 20:12
  • 2
    @Noldorin, реализация C # CodeDOM фактически не создает сборку в памяти. Вы можете включить флаг для него, но он игнорируется. Вместо этого он использует временный файл. – Matthew Olenik 5 May 2009 в 20:26
  • 3
    @Matt: Да, хороший момент - я забыл об этом. Тем не менее, он по-прежнему значительно упрощает процесс (делает его эффективным появляется , как если бы сборка была сгенерирована в памяти) и предлагает полный управляемый интерфейс, который намного приятнее, чем работа с процессами. – Noldorin 5 May 2009 в 23:07
  • 4
    Кроме того, CodeDomProvider - это просто класс, который в любом случае вызывает csc.exe. – justin.m.chase 1 July 2011 в 08:05

Вы можете скомпилировать фрагмент кода C # в память и сгенерировать байты сборки с Roslyn. Это уже упоминалось, но стоило бы добавить пример Roslyn для этого здесь. Ниже приведен полный пример:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;

namespace RoslynCompileSample
{
    class Program
    {
        static void Main(string[] args)
        {
            SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(@"
                using System;

                namespace RoslynCompileSample
                {
                    public class Writer
                    {
                        public void Write(string message)
                        {
                            Console.WriteLine(message);
                        }
                    }
                }");

            string assemblyName = Path.GetRandomFileName();
            MetadataReference[] references = new MetadataReference[]
            {
                MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
                MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location)
            };

            CSharpCompilation compilation = CSharpCompilation.Create(
                assemblyName,
                syntaxTrees: new[] { syntaxTree },
                references: references,
                options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

            using (var ms = new MemoryStream())
            {
                EmitResult result = compilation.Emit(ms);

                if (!result.Success)
                {
                    IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic => 
                        diagnostic.IsWarningAsError || 
                        diagnostic.Severity == DiagnosticSeverity.Error);

                    foreach (Diagnostic diagnostic in failures)
                    {
                        Console.Error.WriteLine("{0}: {1}", diagnostic.Id, diagnostic.GetMessage());
                    }
                }
                else
                {
                    ms.Seek(0, SeekOrigin.Begin);
                    Assembly assembly = Assembly.Load(ms.ToArray());

                    Type type = assembly.GetType("RoslynCompileSample.Writer");
                    object obj = Activator.CreateInstance(type);
                    type.InvokeMember("Write",
                        BindingFlags.Default | BindingFlags.InvokeMethod,
                        null,
                        obj,
                        new object[] { "Hello World" });
                }
            }

            Console.ReadLine();
        }
    }
}
44
ответ дан tugberk 25 August 2018 в 10:07
поделиться
  • 1
    Это тот же код, который использует компилятор C #, который является самым большим преимуществом. Сложность - относительный термин, но компиляция кода во время выполнения - это сложная работа, которую нужно делать в любом случае. Однако приведенный выше код не является сложным. – tugberk 14 November 2015 в 10:45
Другие вопросы по тегам:

Похожие вопросы: