2009-01-27 50 views
6

基本思想是取一個字符串並對照XML文件(或任何LINQed提供者)進行評估。是否可以在運行時動態/評估包含有效LINQ的字符串?

我發現這個LINQ Dynamic Query Library。只是粗略瀏覽了下載包中單個頁面的文檔。這似乎是添加了擴展方法來參數化部分LINQ查詢。有誰知道這是否做動態評估?

有沒有什麼辦法可以做(假設有一些方法可以用XML文件中的數據對類進行播種)?

ClassFromWishfulThinking.Evaluate(sLinqQuery); 
+0

我投了你的問題,僅僅因爲它在我看到它時坐在-1。不太清楚爲什麼有人會投下你的問題... – GregD 2009-01-27 14:59:04

回答

3

這一定是可能的,因爲Linqpad做到了!

看着how it works page是有點頭腦彎曲,我不確定這是你想要做的生產代碼,除非你真的無法避免它。

沒有框架方法只是做你想做的事情,我可以說由於.NET的工作方式而具有相當高的信心。您必須使用LinqPad所使用的csharpcodeprovider來調用編譯器。

您可能可以更改Linq動態查詢庫來執行您所需的操作。

+0

這不是生產代碼..而是試圖做一個簡單版本的Linqpad ..但是反對XML而不是SQL。 – Gishu 2009-01-27 16:46:07

0

很多LinqToXml都是由字符串驅動的。例如,Elements extension method將採用一個字符串並查找具有該名稱的所有子元素。

如果您的查詢以字符串開頭(而不是Queryable/Enumerable上的方法調用),那麼它並不是一個真正的linq查詢 - 不過是別的。也許XPath可以提供幫助。

2

我已經在VB中使用這段代碼來評估運行時字符串中包含的代碼......您需要將它轉換爲C#,但沒有理由不能傳遞包含LINQ的字符串表達。您需要稍微修改FuncString以允許使用LINQ,因爲我只引用System.Math。我用它在運行時(大多是數學)表現的評價,但我想它可以修改/擴展到評估在.NET框架的幾乎任何東西......

Function Evaluate(ByVal Expression As String, ByVal Args() As Object) As Object 

    If Expression.Length > 0 Then 

     'Replace each parameter in the calculation expression with the correct values 
     Dim MatchStr = "{(\d+)}" 
     Dim oMatches = Regex.Matches(Expression, MatchStr) 
     If oMatches.Count > 0 Then 
      Dim DistinctCount = (From m In oMatches _ 
           Select m.Value).Distinct.Count 
      If DistinctCount = Args.Length Then 
       For i = 0 To Args.Length - 1 
        Expression = Expression.Replace("{" & i & "}", Args(i)) 
       Next 
      Else 
       Throw New ArgumentException("Invalid number of parameters passed") 
      End If 
     End If 

     Dim FuncName As String = "Eval" & Guid.NewGuid.ToString("N") 
     Dim FuncString As String = "Imports System.Math" & vbCrLf & _ 
            "Namespace EvaluatorLibrary" & vbCrLf & _ 
            " Class Evaluators" & vbCrLf & _ 
            " Public Shared Function " & FuncName & "() As Double" & vbCrLf & _ 
            "  " & Expression & vbCrLf & _ 
            " End Function" & vbCrLf & _ 
            " End Class" & vbCrLf & _ 
            "End Namespace" 

     'Tell the compiler what language was used 
     Dim CodeProvider As CodeDomProvider = CodeDomProvider.CreateProvider("VB") 

     'Set up our compiler options... 
     Dim CompilerOptions As New CompilerParameters() 
     With CompilerOptions 
      .ReferencedAssemblies.Add("System.dll") 
      .GenerateInMemory = True 
      .TreatWarningsAsErrors = True 
     End With 

     'Compile the code that is to be evaluated 
     Dim Results As CompilerResults = _ 
      CodeProvider.CompileAssemblyFromSource(CompilerOptions, FuncString) 

     'Check there were no errors... 
     If Results.Errors.Count > 0 Then 
     Else 
      'Run the code and return the value... 
      Dim dynamicType As Type = Results.CompiledAssembly.GetType("EvaluatorLibrary.Evaluators") 
      Dim methodInfo As MethodInfo = dynamicType.GetMethod(FuncName) 
      Return methodInfo.Invoke(Nothing, Nothing) 
     End If 

    Else 
     Return 0 

    End If 

    Return 0 

End Function 

Sub Main() 
    'In a real application, this string would be loaded from a database 
    'it would be stored by some calculation administrator... 
    Dim Expr As String = " If ({0} < 20000) Then" & vbCrLf & _ 
         " Return Max(15, Min(75,0.12*{0}))" & vbCrLf & _ 
         " Else" & vbCrLf & _ 
         " Return Max(75,0.05*{0})" & vbCrLf & _ 
         " End If" 

    Dim Args As New List(Of String) 
    While True 
     'This value would be loaded from some data interpreter for inclusion 
     'in the calculation... 
     Dim Val As String = Console.ReadLine 
     Args.Clear() 
     If IsNumeric(Val) Then 
      Args.Add(Val) 
      Dim dblOut As Object = Evaluate(Expr, Args.ToArray) 
      Console.WriteLine(dblOut) 
     Else 
      Exit While 
     End If 
    End While 

End Sub 

沒有理由你不能稍微修改函數定義,以便它可以作爲字符串的擴展名,以便讓您像這樣調用它:

Dim LinqString = "from c in myLinqData where c.SomeField.Equals(""somevalue"") select c" 
Dim output = LinqString.Evaluate 
相關問題