Возможно ли динамически компилировать и выполнять fragmentы кода C #?

Мне было интересно, можно ли сохранить fragmentы кода C # в текстовый файл (или любой входной stream), а затем выполнить их динамически? Предполагая, что мне предоставлено, будет компилироваться в любом блоке Main (), можно ли скомпилировать и / или выполнить этот код? Я бы предпочел скомпилировать его по соображениям производительности.

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

6 Solutions collect form web for “Возможно ли динамически компилировать и выполнять fragmentы кода C #?”

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

Вот краткий пример из блога 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() { { "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().ToList().ForEach(error => Console.WriteLine(error.ErrorText)); } } 

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

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

Вы можете скомпилировать fragment кода 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 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(); } } } 

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

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

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

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

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

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

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

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

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

EDIT : Или еще лучше, используйте CodeDOM, как предложил Нолдорин …

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

Обнаружено, что это полезно – гарантирует, что скомпилированная assembly ссылается на все, на что вы в настоящее время ссылаетесь, так как есть хороший шанс, что вы хотите, чтобы C #, который вы компилируете, использовал некоторые classы и т. Д. В коде, который испускает это:

  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 class, чье имя хранилось в строке className , которая имела один открытый статический метод с именем Get() , который возвращался с типом StoryDataIds . Вот как выглядит этот метод:

  var tempType = asm.GetType(className); var ids = (StoryDataIds)tempType.GetMethod("Get").Invoke(null, null); 
Interesting Posts

Лучший способ отслеживать мое интернет-соединение, отличное от ping

Windows 7 – VBS Script для изменения последнего входа в систему

Является ли List подclassом List ? Почему Java-дженерики не являются неявно полиморфными?

Отслеживание причины ошибки bluescreen (код 124)

Переход на последнюю вкладку * используется * в Chrome

Windows 7 считает, что часовой пояс UTC + 1 в Амстердаме – это часовой пояс UTC + 10

Ubuntu не загружается (застрял на всплеске)

Как уменьшить зону прокрутки в области трекпада Windows 8?

Могу ли я загружать и запускать Windows XP с флеш-накопителя USB?

Первая попытка воспроизвести любой звук после загрузки приводит к 30-секундной задержке

Показать дубликаты данных с awk print $ 2, $ 3, $ 4 в одной строке

Имеет ли смысл устанавливать антивирус в режиме Windows XP?

Как анализировать «запуск из спящего режима»

Могу ли я писать на японском языке свой трекпад?

Как обновить графический интерфейс из другого streamа?

Давайте будем гением компьютера.