Как создать динамический запрос linq и не упасть по исключению: На переменную "имя" типа "имя_типа" имеется ссылка из области "", но она не определена

211
10 ноября 2021, 14:20

Для коллекции "records" состоящей из экземпляров класса FileCabinetRecord

`public class FileCabinetRecord
{
    public short Status { get; set; } = 0;
    public int Id { get; set; }
    public char Sex { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public decimal Salary { get; set; }
    public DateTime DateOfBirth { get; set; }
}`

я пытаюсь создать команду where, наподобие одноименной команды из sql, но при компиляции делегата из дерева выражений программа падает с исключением:

"InvalidOperationException: На переменную "record" типа "FileCabinetRecord" имеется ссылка из области "", но она не определена"

В команде предусмотрено использование только сравнений на эквивалентность, никаких иных наподобие > < != .

Просмотрел кучу примеров, но понять не могу - где я ошибаюсь...

Исключение выбрасывается при попытке скомпилировать whereExpr в whereDelegate.

Вот мой код.

Это моё первое знакомство с рефлексией и деревьями выражений. Пожалуйста, покажите где я ошибся и подскажите как поправить код в целом.

Строка с выражениями следующая: "select firstname, salary, sex where firstname = 'qwer1' or firstname = 'qwer2' and id = '1' or id = '2'".

В метод Where я отдавал только часть строки, стоящую после "where".

P.S. с регулярными выражениями я "на вы".

public static IEnumerable<FileCabinetRecord> Where(string expressions, IEnumerable<FileCabinetRecord> records)
{
    Regex regex = new Regex(@"([a-z]{2,}\s*=\s*\p{P}+[\w|\/]*\p{P}+)*([a-z]{2,})*", RegexOptions.IgnoreCase);
    var matches = regex.Split(expressions).Select(r => r).Where(r => !string.IsNullOrEmpty(r) & !string.IsNullOrWhiteSpace(r)).ToList();
    BinaryExpression left, right, resulted = default(BinaryExpression);
    var record = Expression.Parameter(typeof(FileCabinetRecord), "record");
    int i = 0;
    while (i < matches.Count)
    {
        if (i == 0)
        {
            left = EqualsExpressionFactory(matches[0]);
            right = EqualsExpressionFactory(matches[2]);
            resulted = matches[1].Equals("and", StringComparison.InvariantCultureIgnoreCase) ? MakeAndAlsoExpr(left, right) : MakeOrElseExpr(left, right);
            i += 3;
        }
        else
        {
            left = resulted;
            right = EqualsExpressionFactory(matches[i + 1]);
            resulted = matches[i].Equals("and", StringComparison.InvariantCultureIgnoreCase) ? MakeAndAlsoExpr(left, right) : MakeOrElseExpr(left, right);
            i += 2;
        }       
    }
    var whereExpr = Expression<Func<FileCabinetRecord, bool>>.Lambda<Func<FileCabinetRecord, bool>>(resulted, record);
    var selectExpr = Expression<Func<FileCabinetRecord, FileCabinetRecord>>.Lambda<Func<FileCabinetRecord, FileCabinetRecord>>(record, record);
    var whereDelegate = whereExpr.Compile(); // Тут выбрасывается исключение
    var selectDelegate = selectExpr.Compile(); // До сюда даже не дошло ни разу
    var res = records.Select(selectDelegate).Where(whereDelegate);
    return res;
}
public static BinaryExpression MakeAndAlsoExpr(Expression left, Expression right)
{
    return Expression.AndAlso(left, right);
}
public static BinaryExpression MakeOrElseExpr(Expression left, Expression right)
{
    return Expression.OrElse(left, right);
}
public static BinaryExpression EqualsExpressionFactory(string expression)
{
    var args = expression.Split(new char[] { '=' }, 2).Select(s => s.Trim(' ', '\'')).ToList();
    var propName = args[0].ToUpperInvariant();
    string value = args[1];
    BinaryExpression be;
    switch (propName)
    {
        case "ID":
            be = MakeBinary(propName, int.Parse(value));
            break;
        case "SEX":
            be = MakeBinary(propName, char.Parse(value));
            break;
        case "FIRSTNAME":
        case "LASTNAME":
            be = MakeBinary(propName, value);
            break;
        case "SALARY":
            be = MakeBinary(propName, decimal.Parse(value));
            break;
        case "DATEOFBIRTH":
            be = MakeBinary(propName, DateTime.Parse(value));
            break;
        default:
            return null;
    }
    return be;
}
public static BinaryExpression MakeBinary<T>(string propName, T value)
{
    MemberInfo property = properties[propName];
    MemberExpression propertyExpr = Expression.MakeMemberAccess(Expression.Parameter(typeof(FileCabinetRecord), "record"), property);
    BinaryExpression Equals = Expression.Equal(propertyExpr, Expression.Constant(value, propertyExpr.Type));
    return Equals;
}
public static Type recordType = typeof(FileCabinetRecord);
public static Dictionary<string, MemberInfo> properties = new Dictionary<string, System.Reflection.MemberInfo>
    {
        {"ID", recordType.GetProperty("Id")},
        {"SEX", recordType.GetProperty("Sex")},
        {"FIRSTNAME", recordType.GetProperty("FirstName")},
        {"LASTNAME", recordType.GetProperty("LastName")},
        {"SALARY", recordType.GetProperty("Salary")},
        {"DATEOFBIRTH", recordType.GetProperty("DateOfBirth")},
    };
READ ALSO
C# AnglesSharp response error &quot;Too Many Requests&quot;

C# AnglesSharp response error "Too Many Requests"

Я делаю парсер, использую AnglesSharp и при попытке получить ресурсы сайта он кидает мне ошибку, мол слишком много запросов, хотя в этой тестовой...

206
Как передать список, состоящий из &#39;{\$_POST[&#39;Name&#39;]}&#39; в VALUES?

Как передать список, состоящий из '{\$_POST['Name']}' в VALUES?

Всем приветЧтение руководства и поиск в интернете не помогают мне, видимо потому что плохо формулирую вопрос

139
Wordpress добавление функции на хук save_post

Wordpress добавление функции на хук save_post

Проблема: После того, как я повесил функцию на хук save_post - сама функция и хук отрабатывается полностьюЗапись и ее изменения сохраняются

213
Замeна Логина через RedBeanPHP

Замeна Логина через RedBeanPHP

Вроде написано как надо, но данные в базе не изменяются

104