Разрешение параметров LINQ, которые были переданы методу, в котором выражение LINQ имеет вид - PullRequest
2 голосов
/ 23 сентября 2011

Я работаю над переводчиком LINQ to SQL.Он должен переводить запросы LINQ в SQL.Я сосредоточен на создании ГДЕ части запроса.Я перебираю дерево выражений LINQ, и затем я сталкиваюсь с проблемой, которую я не могу получить к значению фактического параметра, переданного методу, содержащему вызов LINQ.

ПРИМЕЧАНИЕ. Я не использую LINQ to SQL,ни Entity Framework, ни NHibernate, потому что я просто не могу, так как в игре присутствует система VB6 Legacy.

Так что я пытаюсь добиться, чтобы вызвать где-то на высоком уровне это:

int? parameterForCall = cmb.SelectedValue;

Тогда у меня есть метод, подобный этому, и он находится в ExpenseDAL классе, который вызывает BaseDAL<Expense>.GetAll(X):

public IList<Expense> GetAll(int? parameterForCall)
{
    IList<Expense> expenses = BaseDAL<Expense>.GetAll(t => t.Fixed == 
                                                           parameterForCall);
}

GetAll метод имеет такую ​​подпись:

public static IList<T> GetAll(Expression<Func<T, bool>> predicate = null);

Затем я вызываю GetCondition метод, который преобразует выражение в SQL:

private static string GetCondition(Expression predicate = null);

Это рекурсивная функция.В нем я попадаю в ситуацию, в которой мне нужно получить параметр, который я передал выражению GetAll с именем parameterForCall.

Проблема в том, что я могу написать это:

dynamic value = (predicate as ConstantExpression);

И в ImmediateWindow я вижу это значение. Значение записывается так:

{FMC.Proxy.Common.BaseDAL.}
    parameterForCall: 19

Но я не могу добраться до значения 19. И я хочу, чтобы я мог преобразовать его в значение, чтобы положитьв строку SQL.

Кто-нибудь знает, как получить значение 19, чтобы я мог использовать его в коде?

Ответы [ 3 ]

1 голос
/ 23 сентября 2011

Вам просто нужно получить свойство из dynamic, которое вы уже получили:

dynamic value = (predicate as ConstantExpression);
int? parameterForCall = value.parameterForCall;

Если вы не знаете имя параметра (и, возможно, тип), вы можете использовать отражение.Требуемый параметр существует как открытое поле объекта, возвращаемого ConstantExpression.Value.Это нигде не указано, поэтому используйте его на свой страх и риск.

Этот небольшой фрагмент кода демонстрирует, что:

class Expense { public int Fixed { get; set; } }

void Test(int? parameterForCall) {
  Expression<Func<Expense, bool>> predicate = t => t.Fixed == parameterForCall;
  var parameter = (
    (ConstantExpression) (
      (MemberExpression) (
        (BinaryExpression) predicate.Body
      ).Right
    ).Expression
  ).Value;
  var fieldInfo = parameter.GetType().GetFields().First();
  var name = fieldInfo.Name;
  var value = fieldInfo.GetValue(parameter);
  Console.WriteLine(name + " = " + value);
}

Если вы выполните Test(19), вывод будет parameterForCall = 19.

1 голос
/ 23 сентября 2011

В моем ответе предполагается - и ваш вопрос подтверждает это предположение - что предикат, переданный в GetCondition, имеет тип ConstantExpression.

Получить это значение нетривиально, поскольку parameterForCall записывается в автоматически сгенерированный класс.Вы можете увидеть это, когда посмотрите на вывод (predicate as ConstantExpression).Value.GetType().В моем случае это выводит:

UserQuery+<>c__DisplayClass0

Этот класс, в свою очередь, имеет открытое поле с именем parameterForCall.Теперь у вас есть две возможности получить это значение:

  1. Вы знаете имя этого поля, потому что вы контролируете метод, в котором создается это выражение.В этом случае вы можете использовать этот код для получения значения:

    var constantExpression = (ConstantExpression)predicate;
    dynamic autoGeneratedClass = constantExpression.Value;
    object value = autoGeneratedClass.parameterForCall;
    

    value.GetType() вернет System.Int32, а value будет упакованным целым числом со значением 19.

  2. Вы не знаете название этого поля.В этом случае это сложнее.Вы можете использовать отражение, чтобы получить значение единственного открытого видимого поля, но если вы сделаете это, вы бы сделали много предположений об автоматически сгенерированном классе.

0 голосов
/ 23 сентября 2011

Надеюсь, этот ответ Stackoverflow поможет

деревья выражений linq получить значение параметра?

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

Хотя следите за ухудшением производительности.Удачи.

...