2015-06-16 2 views
-1

Я использую Roslyn, чтобы попытаться скомпилировать и запустить код во время выполнения. У меня есть код, который я нашел в Интернете, и он несколько работает.Compile C# Roslyn

public Type EvalTableScript(string Script, CRMMobileFramework.EnbuUtils EnbuUtils, CRMMobileFramework.Includes.DBAdapter dbConn) 
{ 
    var syntaxTree = SyntaxTree.ParseText(Script); 
    var compilation = Compilation.Create("EnbuScript.dll", 
     options: new CompilationOptions(outputKind: OutputKind.DynamicallyLinkedLibrary), 
     references: new[] 
     { 
      new MetadataFileReference(typeof(object).Assembly.Location), 
      new MetadataFileReference(typeof(EnbuUtils).Assembly.Location), 
      new MetadataFileReference(typeof(DBAdapter).Assembly.Location), 
      MetadataFileReference.CreateAssemblyReference("System.Data"), 
      MetadataFileReference.CreateAssemblyReference("System.Linq"), 
      MetadataFileReference.CreateAssemblyReference("System"), 
      MetadataFileReference.CreateAssemblyReference("System.XML") 


     }, 
     syntaxTrees: new[] { syntaxTree }); 
    var diagnostics = compilation.GetDiagnostics(); 


    foreach (var diagnostic in diagnostics) 
    { 
     Console.WriteLine("Error: {0}", diagnostic.Info.GetMessage()); 
    } 

    Assembly assembly; 
    using (var stream = new MemoryStream()) 
    { 

     EmitResult emitResult = compilation.Emit(stream); 
     assembly = Assembly.Load(stream.GetBuffer()); 
    } 


    Type ScriptClass = assembly.GetType("EnbuScript"); 
    // Pass back the entire class so we can call it at the appropriate time. 
    return ScriptClass; 
} 

Тогда я пытаюсь назвать это:

string Script = @" 
using System; 
using System.Data; 
using System.IO; 
using System.Linq; 

public class EnbuScript 
{ 


    public string PostInsertRecord(CRMMobileFramework.EnbuUtils EnbuUtils,CRMMobileFramework.Includes.DBAdapter dbConn) 
    { 
     string ScriptTable = ""QuoteItems""; 
     DataSet EntityRecord = dbConn.FindRecord(""*"", ScriptTable, ""QuIt_LineItemID='"" + EnbuUtils.GetContextInfo(ScriptTable) + ""'"", """", 1, 1, false); 
     string OrderId = EntityRecord.Tables[""item""].Rows[0][""QuIt_orderquoteid""].ToString(); 

     string UpdateOrderTotalCommand = ""UPDATE Quotes SET Quot_nettamt = (select SUM(QuIt_listprice * quit_quantity) from QuoteItems where quit_orderquoteid = "" + OrderId + "") where Quot_OrderQuoteID = "" + OrderId; 
     dbConn.ExecSql(UpdateOrderTotalCommand); 
     return ""Complete""; 
    } 

}"; 


Type EnbuScript = EnbuUtils.EvalTableScript(Script, EnbuUtils, dbConn); 
MethodInfo methodInfo = EnbuScript.GetMethod("InsertRecord"); 
object[] parameters = { EnbuUtils, dbConn }; 
string InsertRecordResult = methodInfo.Invoke(null, parameters).ToString(); 

Как вы можете видеть, я возиться с попыткой передать параметры компиляции. В принципе у меня есть 4 функции, которые мне нужно поддерживать, которые войдут в строку. То, что я пытаюсь сделать, это создать класс для этих 4 функций и скомпилировать их и запустить. Эта часть работает. Что мне теперь нужно сделать, так это передать экземпляры класса. В коде вы увидите dbConn, который в основном связан с моей базой данных. Мне нужно передать экземпляр этого метода, который я вызываю во время выполнения, поэтому он имеет правильный контекст.

У меня есть другая реализация этого, когда я использую сессию Roslyn. Сначала я попытался использовать это и переопределить свою функцию во время выполнения, но это тоже не сработало. Ниже я попытался:

public static void EvalTableScript(ref EnbuUtils EnbuUtils, DBAdapter dbConn, string EvaluateString) 
{ 
    ScriptEngine roslynEngine = new ScriptEngine(); 
    Roslyn.Scripting.Session Session = roslynEngine.CreateSession(EnbuUtils); 

    Session.AddReference(EnbuUtils.GetType().Assembly); 
    Session.AddReference(dbConn.GetType().Assembly); 
    Session.AddReference("System.Web"); 
    Session.AddReference("System.Data"); 
    Session.AddReference("System"); 
    Session.AddReference("System.XML"); 
    Session.ImportNamespace("System"); 
    Session.ImportNamespace("System.Web"); 
    Session.ImportNamespace("System.Data"); 
    Session.ImportNamespace("CRMMobileFramework"); 
    Session.ImportNamespace("CRMMobileFramework.Includes"); 

    try 
    { 
     var result = (string)Session.Execute(EvaluateString); 
    } 
    catch (Exception ex) 
    { 

    } 
} 

Я попытался назвать это с помощью:

    string PostInsertRecord = "" + 
       " public override void PostInsertRecord() " + 
       "{ " + 
        " string ScriptTable = \"QuoteItems\"; " + 
        "DataSet EntityRecord = dbConn.FindRecord(\"*\", ScriptTable, \"QuIt_LineItemID='\" + EnbuUtils.GetContextInfo(ScriptTable) + \"'\", \"\", 1, 1, false); " + 
        "string OrderId = EntityRecord.Tables[\"item\"].Rows[0][\"QuIt_orderquoteid\"].ToString(); " + 

        "string UpdateOrderTotalCommand = \"UPDATE Quotes SET Quot_nettamt = (select SUM(QuIt_listprice * quit_quantity) from QuoteItems where quit_orderquoteid = \" + OrderId + \") where Quot_OrderQuoteID = \" + OrderId; " + 
        "dbConn.ExecSql(UpdateOrderTotalCommand); " + 
       "} "; 

функция объявлена ​​как публичной виртуальной пустоты в классе EnbuUtils, но он говорит, что не имеет подходящей метод для переопределения.

Безопасно сказать, я в тупике! Любая помощь ценится! Спасибо

ответ

-1

Я получил это в конце - этот первый метод был очень близок к тому, что мне действительно нужно. Изменен метод на static и ему пришлось добавить несколько ссылок, включая полное пространство имен.