Можно ли оценить строку, содержащую действительный LINQ, динамически / во время выполнения? - PullRequest
6 голосов
/ 27 января 2009

Основная идея - взять строку и сравнить ее с файлом XML (или любым поставщиком LINQed)

Я нашел это Библиотека динамических запросов LINQ . Просто бегло взглянул на документацию, которая представляет собой одну страницу в комплекте загрузки. Похоже, это добавляет методы расширения для параметризации частей LINQ Query. Кто-нибудь знает, выполняет ли это динамическую оценку?

Есть ли способ просто сделать это (при условии, что есть какой-то способ заполнить класс данными из файла XML)?

ClassFromWishfulThinking.Evaluate(sLinqQuery);

Ответы [ 3 ]

3 голосов
/ 27 января 2009

Это должно быть возможно, потому что Linqpad делает это!

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

Не существует фреймворкового метода, который бы просто делал то, что вы хотите, я могу сказать это с довольно высокой степенью уверенности из-за того, как работает .net. Вы должны вызывать компилятор, используя csharpcodeprovider , как это делает LinqPad.

Возможно, вы сможете изменить библиотеку динамических запросов Linq, чтобы она делала то, что вам нужно.

2 голосов
/ 27 января 2009

У меня есть этот код в VB для оценки кода, содержащегося в строке во время выполнения ... вам нужно перевести его на C #, но нет причины, по которой вы не могли просто передать строку, содержащую выражение LINQ , Вам нужно немного изменить FuncString, чтобы разрешить использование LINQ, поскольку я ссылаюсь только на System.Math. Я использую его для оценки (в основном математических) выражений во время выполнения, но я полагаю, что его можно модифицировать / расширить, чтобы оценить практически все в .NET Framework ...

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
0 голосов
/ 27 января 2009

Большая часть LinqToXml в любом случае определяется строками. Например, метод расширения Elements возьмет строку и найдет все дочерние элементы с этим именем.

Если ваш запрос начинается как строка (а не как вызов метода в Queryable / Enumerable), то на самом деле это не запрос linq, а что-то другое. Может быть XPath может помочь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...