2010-08-11 20 views
1

J'ai une collection d'objets personnalisés (actifs) que je veux regrouper avec LINQ. Un objet personnalisé possède des propriétés standard telles que id, name et cost. Lors du regroupement je veux calculer le coût pour chaque groupe, donc je me sers petit truc comme ça:objet de clonage sur le regroupement linq - copier le constructeur substituer

from a in assets 
group a by a.AssetId into ga 
select new Asset() 
       { 
        AssetId = ga.Key, 
        Cost = ga.Select(gg=>gg.Cost).Sum() 
       } 

Ok, tout est bien ici. Mais ... afin d'initialiser les propriétés de commande ainsi, j'utilise copie contructor et calcul des coûts ainsi ...

from a in assets 
group a by a.AssetId into ga 
select new Asset(ga.FirstOrDefault()) 
       { 
        AssetId = ga.Key, 
        Cost = ga.Select(gg=>gg.Cost).Sum() 
       } 

Alors maintenant, je reçois ensemble d'actifs regroupés par id, avec toutes les propriétés copiées à partir un premier actif dans un groupe avec un coût groupé calculé. Mais ... pour ce faire j'ai besoin d'écrire pour chaque objet utilisant ce type de groupement, un constructeur de copie avec 'toutes les initialisations de propriétés' qui dans mon cas est surcharge car il y a des objets avec plus de 20 propriétés.

J'ai essayé d'utiliser trick clone à partir d'un lien:

Deep cloning objects

dans la requête du groupe LINQ, mais sans succès.

Ma question: y a-t-il une façon meilleure/plus élégante d'accomplir cela?

Merci

Répondre

2

Si vous n'avez pas besoin de les copier en profondeur, vous pouvez utiliser la méthode MemberwiseClone. L'implémentation (provenant de la classe Object) & vous donne une copie superficielle. Donc, la ligne new Asset(ga.FirstOrDefault()) deviendra ((Asset)(ga.FirstOrDefault().MemberwiseClone())). Toutefois, étant une copie superficielle, [First Asset] .SomeObject pointerait sur [Grouped Asset] .SomeObject et les modifications de l'un refléteraient à l'autre.

modifié pour inclure la méthode d'assistance décrite dans les commentaires:

static T CloneAndUpdate<T>(T t, Action<T> updater) where T: class 
{ 
T clone = null; // Use reflection/serialization to create shallow/deep clone 
updater(clone); 
return clone; 
} 

Maintenant, vous pouvez utiliser la méthode comme suit:

select Utility.CloneAndUpdate(ga.FirstOrDefault(), a => 
      { 
       AssetId = ga.Key, 
       Cost = ga.Select(gg=>gg.Cost).Sum() 
      }) 
+0

Oops! Je remarque que vous voulez utiliser des initialiseurs d'objet - pas sûr qu'ils fonctionneraient sur l'instance d'Asset sans utiliser de constructeur. – VinayC

+0

La seule façon que je peux penser est d'ajouter un constructeur de copie qui utilise MemberwiseClone() - qui réduira au moins le temps d'écrire le constructeur de copie. Une autre façon serait d'écrire une méthode statique telle que - statique T CloneAndUpdate (T t, Action updater) où T: classe { T clone = ...;/* Utiliser la réflexion/sérialisation pour créer un clone */ updater (clone); clone de retour; } puis utilisez comme ---- select Utility.CloneAndUpdate (ga.FirstOrDefault(), a => { assetId = ga.Key, Coût = ga.Select (= gg> gg.Cost) .sum ( }) – VinayC

+0

oui, c'est mon problème .. merci quand même, belle réponse – Marko