Компиляция с CodeDom

Я начал немного экспериментировать с CodeDom и сделал простое приложение, которое собирает исходный код из пользовательского ввода и пытается скомпилировать его с синтаксисом C#.

Для тех, кто хочет попробовать весь процесс, введите end..., чтобы закончить ввод исходного кода.

Вот пример:

using System;
using System.Collections;
using System.Reflection;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.CSharp;
using System.CodeDom.Compiler;

namespace CodeDomTest
{
    class Program
    {
        static void Main(string[] args)
        {
            getTestCode();
        }

        public static Assembly getTestCode()
        {
            CompilerParameters CompilerOptions = new CompilerParameters(
                assemblyNames: new String[] { "mscorlib.dll", "System.dll", "System.Core.dll" }, 
                outputName: "test.dll", 
                includeDebugInformation: false) 
            { TreatWarningsAsErrors = true, WarningLevel = 0, GenerateExecutable = false, GenerateInMemory = true };
            List<String> newList = new List<String>();
            String a = null;
            while(a != "end...")
            {
                a = Console.ReadLine();
                if (!a.Equals( "end..."))
                    newList.Add(a);
            }
            String[] source = { "class Test {static void test() {System.Console.WriteLine(\"test\");}}" };
            source = newList.ToArray();
            CSharpCodeProvider zb = new CSharpCodeProvider(new Dictionary<String, String> { { "CompilerVersion", "v4.0" } });
            CompilerResults Results = zb.CompileAssemblyFromSource(CompilerOptions, source);
            Console.WriteLine(Results.Errors.HasErrors);
            CompilerErrorCollection errs = Results.Errors;
            foreach(CompilerError z in errs) 
            {
                Console.WriteLine(z.ErrorText);
            }
            if (!(errs.Count > 0)) 
            {
                AssemblyName assemblyRef = Results.CompiledAssembly.GetName();
                AppDomain.CurrentDomain.Load(assemblyRef);
                //foreach (String a in )
                Console.WriteLine(Results.CompiledAssembly.FullName.ToString());
                Type tempType = Results.CompiledAssembly.GetType("Test");
                MethodInfo tempMethodInfo = tempType.GetMethod("test", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public);
                if (tempMethodInfo != null)
                    tempMethodInfo.Invoke(null,null);
            }
            Console.ReadLine();
            return null;
        }
    }
}

Теперь, как вы можете видеть, в основном он компилирует следующий код:

class Test {static void test() {System.Console.WriteLine(\"test\");}}

Что отлично работает, если вы вводите его так (без ") как пользовательский ввод в программу. Но как только вы вставляете разрыв строки, нажимая ввод после одной готовой строки, компиляция прерывается с несколькими ошибками. Кажется, что он будет оценивать каждую строку как собственную программу, указав следующие операторы:

} expected
Expected class, delegate, enum, interface, or struct
A namespace cannot directly contain members such as fields or methods
A namespace cannot directly contain members such as fields or methods
Type or namespace definition, or end-of-file expected
Type or namespace definition, or end-of-file expected

Для следующего ввода:

class Test 
{
static void test() 
{
System.Console.WriteLine
("test");
}
}

Должен ли я тогда разбивать пользовательские (пользовательские) записи на одну строку?


person prizm1    schedule 18.08.2016    source источник


Ответы (1)


Каждая строка в sources должна содержать полный исходный код, а не одну строку кода. Поскольку вы собираете код построчно в свой исходный массив, вам придется свернуть его в одну строку, а затем добавить эту строку в массив для передачи в CompileAssemblyFromSource Попробуйте следующее:

 while (a != "end...")
 {
     a = Console.ReadLine();
     if (!a.Equals("end..."))
         newList.Add(a);
 }

 string code = string.Join("\r\n", newList);
 string[] source = new string[] { code };
person HasaniH    schedule 18.08.2016
comment
круто, это отлично работает :) но мне кажется довольно сложным, что они требуют свернуть код, так как вы действительно не знаете, чего ожидать, но, с другой стороны, это имеет смысл, поскольку объект называется CompilerResults, хм.. Я буду отметить вас как решение - person prizm1; 18.08.2016
comment
Если вы читали входные данные из файлов, каждая запись в массиве источников должна быть содержимым всего исходного файла, а не одной строки кода. - person HasaniH; 18.08.2016