36 votes

Convertir le type anonyme en nouveau type de tuple c’est 7

La nouvelle version de C# est là, avec la nouvelle fonctionnalité très utile Tuple Types:

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);
}

Est-il un moyen de convertir mon anonyme de type object obj pour le tuple que je veux revenir sans cartographie de la propriété par propriété (en supposant que les noms des propriétés de match)?

Le cadre est dans un ORM, mon SomeType objet a beaucoup d'autres propriétés, et il est mappé à une table avec beaucoup de colonnes. Je veux faire une requête qui apporte juste l'ID et le NOM, j'ai donc besoin de convertir le type anonyme dans un tuple, ou j'ai besoin d'un ORM Linq Fournisseur de savoir comment comprendre un n-uplet et mettre les propriétés liées colonnes dans l'instruction SQL select.

25voto

David L Points 22922

La réponse courte est non, dans la forme actuelle de C#7 il n'est pas dans le cadre de manière à atteindre vos objectifs mot à mot, puisque vous voulez accomplir:

  • Linq-to-entités
  • La cartographie à un sous-ensemble de colonnes
  • En évitant de propriété par propriété de la cartographie d'une coutume, d'anonymes ou de type C#7 tuple par la cartographie directement à a C#7 n-uplet.

Parce qu' Query<SomeType> expose une IQueryable, toute sorte de projection doit être effectuée à une arborescence d'expression .Select(x => new {}).

Il est ouvert roslyn problème pour l'ajout de ce soutien, mais il n'existe pas encore.

En conséquence, jusqu'à ce que ce soutien est ajouté, vous pouvez le connecter manuellement à partir d'un type anonyme à un n-uplet, ou le retour de la totalité de l'enregistrement et de la carte le résultat d'un tuple directement pour éviter les deux démarches, mais c'est évidemment inefficace.


Bien que cette restriction est actuellement cuit dans Linq-to-Entités en raison d'un manque de soutien et de l'incapacité à utiliser paramétrable constructeurs en .Select() de la projection, les deux Linq-to-NHibernate et Linq-to-Sql permettre un hack dans le formulaire de création d'un nouveau System.Tuple dans la .Select() de projection, puis retour à un ValueTuple avec la .ToValueTuple() la méthode d'extension:

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();
}

Depuis Que Le Système.N-uplet peut être mappé à une expression, vous pouvez retourner un sous-ensemble de données à partir de votre table et le cadre pour gérer la cartographie de votre C#7 n-uplet. Vous pouvez ensuite déconstruire les arguments avec toute convention de nommage à vous de choisir:

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

24voto

Patrick Hofman Points 22166

Bien sûr, en créant le tuple à partir de votre expression LINQ:


Selon une autre réponse concernant les tuples pré-C 7, vous pouvez utiliser pour empêcher EF de mélanger les `` choses. (Je n’ai pas beaucoup d’expérience avec EF, mais cela devrait faire:)

11voto

Jeff Mercado Points 42075

Bien que les tuple littéraux ne sont pas actuellement pris en charge dans les arbres d’expression, cela ne signifie pas que le `` type n’est pas. Il suffit de le créer explicitement.

2voto

JakeJ Points 553

Note pour n'importe qui sur une version inférieure de .NET: Si vous êtes sur une version inférieure de .NET que 4.7.2 ou .NET de Base, vous devriez utiliser le Gestionnaire de Package Nuget pour installer le Système.ValueTuple à votre projet.

Alors, voici un exemple de l'obtention d'un n-uplet d'un Linq to SQL de la requête:

var myListOfTuples = (from record1 in myTable.Query()
                     join record2 in myTable2.Query() on record1.Id = record2.someForeignKey
                     select new {record1, record2}).AsEnumerable()
                     .select(o => (o.record1, o.record2))
                     .ToList()

Qui a fonctionné pour moi, cependant, après le check-in, j'ai eu un construire un échec...lisez la suite.

Pour encore plus de plaisir et de jeux, j'ai malheureusement eu une version antérieure de C# sur mon serveur de build pour une raison quelconque. Si je devais revenir en arrière, car il ne reconnaît pas le nouveau tuple format de sur la .sélectionnez(o => (o.record1, o.record2)) ligne (plus précisément, qu'il serait un tuple à cause de la parenthèse autour de o'.record1 et de l'o.record2). Donc, j'ai dû revenir en arrière et type de récupérer un peu plus:

var myListOfAnonymousObjects = (from record1 in myTable.Query()
                     join record2 in myTable2.Query() on record1.Id = record2.someForeignKey
                     select new {record1, record2}).ToList()

var myTuples = new List<Tuple<Record1sClass, Record2sClass>>();
foreach (var pair in myListOfAnonymousObjects)
{
    myTuples.Add(pair.record1, pair.record2);
}
return myTuples;

-2voto

Jackdon Wang Points 9
<pre><code></code><p><strong>Cette méthode, vous pouvez nommer votre élément tuple dans un linq sélectionner</strong></p></pre>

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X