2015-11-19 1 views
1

De Efficient data structure to hold employee's activities?, j'ai une liste de type ActividadEmpleado qui est déclarée comme:Comment passer un résultat LINQ à une méthode?

public string Empleado { get; set; } 
public DateTime Fecha { get; set; } 
public string Actividad { get; set; } 

La variable de requête LINQ réordonne le résultat de la manière dont j'ai besoin, ce qui est de stocker par date et par ActividadEmpleado et une chaîne . Cependant, les types var ne peuvent pas être passés aux méthodes, donc en cherchant ce site, je découvre que je dois créer une classe pour stocker les résultats ou modifier la variable LINQ pour retourner une liste, mais j'ai des problèmes avec la déclaration correcte .

La variable LINQ est:

var queryActividades = listaActividad 
       .GroupBy(a => a.Fecha, (fecha, fechaActividades) => new 
       { 
        Fecha = fecha, 
        FechaActividades = fechaActividades 
         .GroupBy(a => a.Empleado, (nombreEmpleado, actividadesEmpleado) => new 
         { 
          Actividades = actividadesEmpleado, 
          NombreEmpleado = nombreEmpleado 
         }) 
         .OrderBy(a => a.NombreEmpleado) 
       }) 
       .OrderBy(a => a.Fecha); 

Visual Studio dit que queryActividades est:

IOrderedEnumerable<'a> 
Anonymous Types: 
'a new datetime fecha, iorderedenumerable<'b> 
'b new IEnumerable<ActividadEmpleado> Actividades, string NombreEmpleado 

Je dois passer queryActividades à une autre méthode. J'ai essayé de le passer comme un objet, mais je perds les méthodes d'extension telles que Où <> (puis-je le lancer en quelque sorte?)

Je lis aussi que déclarer les résultats en tant que tuple devrait fonctionner, mais je pense que déclarer un nouveau la classe est plus propre.

Je commence avec LINQ, je l'ai évité d'utiliser des structures de données régulières, mais dans ce cas, il est vraiment utile et je voudrais savoir comment soit gérer des types anonymes en eux ou convertir le résultat à une liste régulière

solution finale:

class GrupoActividad 
{ 
    public DateTime Fecha { get; set; } 
    public IEnumerable<Actividad> Actividades { get; set; } 
} 

class Actividad 
{ 
    public IEnumerable<ActividadEmpleado> Actividades { get; set; } 
    public string NombreEmpleado { get; set; } 
} 

var queryActividades = listaActividad 
       .GroupBy(a => a.Fecha, (fecha, fechaActividades) => new GrupoActividad 
       { 
        Fecha = fecha, 
        Actividades = fechaActividades 
         .GroupBy(a => a.Empleado, (nombreEmpleado, actividadesEmpleado) => new Actividad 
         { 
          Actividades = actividadesEmpleado, 
          NombreEmpleado = nombreEmpleado 
         }) 
         .OrderBy(a => a.NombreEmpleado) 
       }) 
       .OrderBy(a => a.Fecha); 

méthode de réception:

var actividades = from a in queryActividades 
         where a.Fecha == fechaCiclo 
         select new { a.Fecha, a.Actividades }; 
      foreach (var item in actividades) 
      { 
       //cycle that holds each day's activities 
       foreach (var empleado in item.Actividades) 
       { 
        //cycle that holds each employee with activities in that day 
        foreach (var actividad in empleado.Actividades) 
        { 
         //final cycle that actually reads the activity 
         ActividadEmpleado actividadEmpleado = (ActividadEmpleado)actividad; 
        } 
       } 
      } 
+0

'OrderBy (a => a.Fecha) .ToList();'? –

+0

Vous ne pouvez pas passer des types anonymes comme des objets tapés, cela ne fonctionnera pas. Pourquoi ne veux-tu pas utiliser un tuple? –

+0

'var' n'est pas un" type "- il laisse simplement le compilateur déduire ce que le type _actual_ est. –

Répondre

4

Actuellement, vous créez une collection basée sur un type anonyme (en fait deux types anonymes), qui ne peut pratiquement pas être transmis à une autre méthode (autre que l'utilisation de la réflexion ou dynamic). La façon la plus propre est de créer un type de béton qui représente la collection - quelque chose comme

puis modifiez votre requête:

var queryActividades = listaActividad 
       .GroupBy(a => a.Fecha, (fecha, fechaActividades) => new ActivityGroup 
       { 
        Fecha = fecha, 
        FechaActividades = fechaActividades 
         .GroupBy(a => a.Empleado, (nombreEmpleado, actividadesEmpleado) => new Activity 
         { 
          Actividades = actividadesEmpleado, 
          NombreEmpleado = nombreEmpleado 
         }) 
         .OrderBy(a => a.NombreEmpleado) 
       }) 
       .OrderBy(a => a.Fecha); 

et le transmettre comme IEnumerable<ActivityGroup>

+0

A dû changer la chaîne Fecha à DateTime fecha dans ActivityGroup, également renommer FechaActividades en activités (ligne 5 de la définition LINQ), mais j'obtiens toujours des erreurs à la compilation: Impossible de convertir actividadesEmpleado en Actividades (ligne 8) et ne peut pas convertir nombreEmpleado à NombreEmpleado (ligne 9). Dois-je supprimer le type IEnumerable dans les classes? – fjleon

+0

@fjleon essayer mon édition - j'ai récupéré les types du type interne à l'envers. Et vous avez besoin de 'IEnumerable <>' puisque les propriétés représentent une collection. –

+0

Erreurs fixes: Impossible de convertir implicitement le type 'System.Collections.Generic.IEnumerable ' en 'System.Collections.Generic.IEnumerable '. En outre, la ligne 8 devrait dire FechaActividades, pas Actividades. S'il vous plaît voir ma question éditée, la méthode qui reçoit queryActividad devrait être en mesure d'appliquer une clause where comme indiqué – fjleon

0

Vous ne pouvez pas passer des types anonymes entre les méthodes; Si vous devez transmettre les données à une autre méthode, vous devez créer un type nommé explicite qui contient les propriétés Actividades et NombreEmpleado, et un autre avec Fecha et FechaActividades.

2

Vous pouvez utiliser le approche présentée par D Stanley. Mais il serait ennuyeux d'avoir à créer de telles classes pour toute requête similaire que vous écrivez dans le futur. Au lieu de cela, vous pouvez présenter comme classe générique pour cela, comme celui-ci

public class Grouping<TKey, TElement> 
{ 
    public TKey Key { get; set; } 
    public IEnumerable<TElement> Elements { get; set; } 
} 

et de l'utiliser au lieu des types anonymes comme celui-ci

var queryActividades = listaActividad 
    .GroupBy(a => a.Fecha, (fecha, fechaActividades) => new Grouping<DateTime, Grouping<string, ActividadEmpleado>> 
    { 
     Key = fecha, 
     Elements = fechaActividades 
      .GroupBy(a => a.Empleado, (nombreEmpleado, actividadesEmpleado) => new Grouping<string, ActividadEmpleado> 
      { 
       Key = nombreEmpleado, 
       Elements = actividadesEmpleado 
      }) 
      .OrderBy(a => a.Key) 
    }) 
    .OrderBy(a => a.Key); 

qui peut être être passé comme IEnumerable<Grouping<DateTime, Grouping<string, ActividadEmpleado>>>.

Comme vous pouvez le voir, il y a un compromis entre réutilisabilité et lisibilité. Fondamentalement, il s'agit d'un Tuple avec un peu plus de noms significatifs. Notez que même si nous ne pouvons pas améliorer la verbosité dans le résultat, on peut utiliser une technique similaire à Tuple.Create pour éliminer la verbosité dans la requête, en ajoutant une classe comme cette

public static class Grouping 
{ 
    public static Grouping<TKey, TElement> Create<TKey, TElement>(TKey key, IEnumerable<TElement> elements) 
    { 
     return new Grouping<TKey, TElement> { Key = key, Elements = elements }; 
    } 
} 

et l'utiliser comme ceci

var queryActividades = listaActividad 
    .GroupBy(a => a.Fecha, (fecha, fechaActividades) => Grouping.Create(
     fecha, fechaActividades 
      .GroupBy(a => a.Empleado, (nombreEmpleado, actividadesEmpleado) => Grouping.Create(
       nombreEmpleado, actividadesEmpleado)) 
      .OrderBy(a => a.Key))) 
    .OrderBy(a => a.Key); 
+0

très intéressant, je vais étudier cela et l'enregistrer quelque part: D, pour l'instant la solution de DStanley (après un petit changement) fonctionne très bien. Peut-être que je vais le changer, j'aime le code plus court :) – fjleon

+0

@fjleon C'est ok, je savais que la solution DStanley est bien au moment où j'ai écrit ce qui précède, mais puisque vous avez dit que vous commencez avec LINQ, a décidé de faire un effort pour vous une option. Heureux que vous l'ayez trouvé intéressant, alors l'effort en vaut la peine :-) A bientôt. –