Преобразование анонимного типа в новый тип кортежа C# 7

новая версия C# есть, с полезными новыми типами кортежей функций:

public IQueryable<T> Query<T>();

public (int id, string name) GetSomeInfo() {
    var obj = Query<SomeType>()
        .Select(o => new {
            id = o.Id,
            name = o.Name,
        })
        .First();

    return (id: obj.id, name: obj.name);
}

есть ли способ преобразовать мой объект анонимного типа obj в кортеж, который я хочу вернуть без сопоставления свойства по свойству (при условии, что имена свойств совпадают)?

контекст находится в ORM, мой объект SomeType имеет много других свойств, и он сопоставляется с таблицей с большим количеством столбцов. Я хочу сделать запрос, который приносит только ID и имя, поэтому мне нужно преобразуйте анонимный тип в кортеж, или мне нужно, чтобы поставщик ORM Linq знал, как понять кортеж и поместить связанные со свойствами столбцы в предложение SQL select.

2 ответов


короткий ответ-нет, в текущей форме C#7 нет способа в рамках для достижения ваших целей дословно, так как вы хотите выполнить:

  • Linq-to-entities
  • отображение в подмножество столбцов
  • избегание свойства путем сопоставления свойств с пользовательским или анонимным типом кортежу C#7 путем сопоставления непосредственно кортежу C#7.

, потому что Query<SomeType> предоставляет IQueryable, любой вид проекции необходимо сделать к дерево выражений .Select(x => new {}).

есть открыть выпуск roslyn для добавления этой поддержки, но она еще не существует.

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


в то время как это ограничение в настоящее время запечено в Linq-to-Entities из-за отсутствия поддержка и невозможность использования параметрических конструкторов в A .Select() проекция, как Linq-to-NHibernate, так и Linq-to-Sql позволяют взломать в виде создания нового System.Tuple на .Select() проекция, а затем возврат ValueTuple с .ToValueTuple () метод расширения:

public IQueryable<T> Query<T>();

public (int id, string name) GetSomeInfo() {
    var obj = Query<SomeType>()
        .Select(o => new System.Tuple<int, string>(o.Id, o.Name))
        .First();

    return obj.ToValueTuple();
}

Начиная С Системы.Кортеж может быть сопоставлен с выражением, вы можете вернуть подмножество данных из таблицы и позволить структуре обрабатывать сопоставление с кортежем C#7. Вы можете затем деконструируйте аргументы с любым соглашением об именах, которое вы выбираете:

(int id, string customName) info = GetSomeInfo();
Console.Write(info.customName);

конечно, создав кортеж из вашего выражения LINQ:

public (int id, string name) GetSomeInfo() {
    var obj = Query<SomeType>()
        .Select(o => (o.Id,o.Name))
        .First();

    return obj;
}

По данным другой ответ Что касается кортежей pre-C# 7, вы можете использовать AsEnumerable() чтобы предотвратить EF, чтобы смешать вещи. (У меня нет большого опыта работы с EF, но это должно сделать:)

public (int id, string name) GetSomeInfo() {
    var obj = Query<SomeType>()
        .AsEnumerable()
        .Select(o => (o.Id,o.Name))
        .First();

    return obj;
}