2009-01-27 14 views
6

Podstawową ideą jest pobranie ciągu znaków i porównanie go z plikiem XML (lub dowolnym dostawcą LINQed).Czy można w sposób dynamiczny oceniać łańcuch zawierający prawidłowy LINQ?

Znalazłem to LINQ Dynamic Query Library. Wystarczyło rzucić okiem na dokumentację, która jest pojedynczą stroną w pakiecie pobierania. Wydaje się, że to jest dodawanie metod rozszerzania do parametryzowania części zapytania LINQ. Czy ktoś wie, czy to robi dynamiczną ocenę?

Czy jest jakiś sposób, aby po prostu zrobić (zakładając, że istnieje sposób do wysiania klasy z danych z pliku XML)?

ClassFromWishfulThinking.Evaluate(sLinqQuery); 
+0

Głosowałem za twoim pytaniem, tylko dlatego, że przy patrzeniu było na -1. Nie jestem do końca pewien, dlaczego ktoś zagłosuje na twoje pytanie ... – GregD

Odpowiedz

3

To musi być możliwe, ponieważ Linqpad to robi!

Patrząc na how it works page jest trochę gięcia umysłu, i nie jestem pewien, czy jest to coś, co chcesz zrobić z kodem produkcyjnym, chyba że naprawdę nie można tego uniknąć.

Nie ma metody ramowej, która po prostu robi to, co chcesz, mogę powiedzieć, że z dość dużym stopniem pewności z powodu działania .net. Musisz zadzwonić do kompilatora używając csharpcodeprovider, tak jak robi to LinqPad.

Być może będziesz w stanie zmienić bibliotekę kwerend dynamicznych Linq, aby zrobić to, czego potrzebujesz.

+0

To nie jest kod produkcyjny .. raczej próbuję zrobić prostą wersję Linqpad .., ale przeciwko XML zamiast SQL. – Gishu

0

Znaczna część z LinqToXml jest napędzana przez ciągi mimo to. Na przykład: Elements extension method pobiera ciąg znaków i znajduje wszystkie elementy podrzędne o tej nazwie.

Jeśli zapytanie zaczyna się od łańcucha znaków (a nie od wywołania metody Queryable/Enumerable), to nie jest to tak naprawdę zapytanie linq - ale coś innego. Może może pomóc XPath.

2

Mam ten kod w VB do oceny kodu zawartego w łańcuchu w czasie wykonywania ... musisz przetłumaczyć go na C#, ale nie ma powodu, dla którego nie można po prostu przekazać ciągu zawierającego LINQ wyrażenie. Musiałbyś nieco zmodyfikować FuncString, aby umożliwić używanie LINQ, ponieważ tylko odwołuję się do System.Math. Używam go do oceny (głównie matematycznych) wyrażeń w czasie wykonywania, ale wyobrażam sobie, to może być modyfikowana/rozszerzony ocenić prawie wszystko w ramach .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 

Nie ma powodu nie mógł zmodyfikuj nieco definicję funkcji, aby mogła funkcjonować jako rozszerzenie ciągu znaków, aby umożliwić wywoływanie go w następujący sposób:

Dim LinqString = "from c in myLinqData where c.SomeField.Equals(""somevalue"") select c" 
Dim output = LinqString.Evaluate 
Powiązane problemy