Преобразовать мой тип значения в эквивалентный - PullRequest
5 голосов
/ 15 марта 2020

У меня есть специальная система отчетности c; У меня нет сведений во время компиляции о типе запросов или об обязательных полях Я мог бы писать деревья выражений во время выполнения, используя фабричные методы System.Linq.Expressions.Expression, и вызывать методы LINQ, используя отражение, но Dynami c LINQ является более простым решением.

Система отчетов должна разрешать запросы, которые возвращают результат левого соединения. В объединенной таблице есть поля, которые NOT NULL в базе данных; но поскольку это LEFT JOIN, эти поля будут содержать NULL для определенных записей. Сгенерированное EF6 выражение относится именно к этому, потому что выражение проецируется на тип значения, не допускающий значения NULL.

Если бы я делал это в LINQ во время компиляции, я бы явным образом приводил к типу NULL:

enum Color { Red, Green,  Blue }

// using System;
// using static System.Linq.Enumerable;
// using System.Linq;

var range = Range(0, 3).Select(x => (Color)x).AsQueryable();
var qry = range.Select(x => (Color?)x);

Dynami c LINQ поддерживает явные преобразования:

// using static System.Linq.Dynamic.Core

var qry1 = range.Select("int?(it)");

, но в запросе может быть указан только конкретный c набор типов . Если я пытаюсь использовать Color в запросе:

var qry2 = range.Select("Color(it)");

, я получаю следующую ошибку:

Не существует применимого метода «Цвет» в типе «Цвет»

и если я пытаюсь явно привести к Color?:

var qry3 = range.Select("Color?(it)");

, я получаю:

Запрошенное значение 'Color' не найдено.

Как это сделать с помощью библиотеки Dynami c LINQ?

Ответы [ 3 ]

7 голосов
/ 18 марта 2020

Dynami c LINQ предоставляет метод Cast, который можно использовать следующим образом:

var range = Enumerable.Range(0,3).Select(x => (Color)x).AsQueryable();
var castDynamic = range.Cast(typeof(Color?)).ToDynamicArray();
castDynamic.Dump();

Вы также можете передать строку с именем типа вывода. Обратите внимание, что для типов, допускающих значение NULL, вам необходимо полное имя типа:

string s = typeof(Color?).FullName;
s.Dump();
var castDynamicFromString = range.Cast(s);
castDynamicFromString.Dump();

Cast также можно использовать в строковом выражении Dynami c LINQ, передавая объект Type как параметр или непосредственно используя имя:

var castInSelect = range.Select($@"Cast(""{s}""").ToDynamicArray();
castInSelect.Dump();

Вывод в LINQPad:

enter image description here

3 голосов
/ 18 марта 2020

Попробуйте это:

var arg0 = Expression.Parameter(typeof(Color), "x");
var expr = DynamicExpressionParser.ParseLambda(new[] { arg0 }, typeof(Color?), "x");
var qry2 = range.AsQueryable().Select("@0(it)", expr);

Также см. https://github.com/StefH/System.Linq.Dynamic.Core/wiki/Dynamic-Expressions#dynamic -lambda-invocation

0 голосов
/ 16 марта 2020

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

public static bool IsValuePresent<T>(int number) where T : Enum
{
    return !Enum.GetValues(typeof(T)).Cast<int>().Contains(number);
}

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

EnumerationConverter.IsValuePresent<Color>(99); //returns False
EnumerationConverter.IsValuePresent<Color>(2); //returns True

Как только False получен в вышеприведенных выражениях, мы можем установить значение равным нулю, иначе мы можем сделать простой преобразователь типа generi c из целого числа в перечисление, как приведенный ниже код.

public static T GetAsEnum<T>(int number) where T : Enum
{
    if (Enum.IsDefined(typeof(T), number))
    {
        return (T)Enum.ToObject(typeof(T), number);
    }
    return default(T);
}

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

...