2010-10-19 8 views
7

J'ai un dictionnaire qui est peuplé et je n'ai aucun contrôle de.Modifier le dictionnaire La valeur est possible. Quelle est la bonne approche?

J'ai besoin de modifier la valeur comment puis-je faire cela?

Je mets un exemple noddy ensemble pour expliquer le problème

class Program 
{ 
    static void Main(string[] args) 
    { 


     Dictionary<Customer, int> CustomerOrderDictionary = new Dictionary<Customer, int>(); 

     CustomerOrderDictionary.Add(new Customer { Id = 1, FullName = "Jo Bloogs" },3); 

     CustomerOrderDictionary.Add(new Customer { Id = 2, FullName = "Rob Smith" },5); 

     //now I decide to increase the quantity but cannot do the below as value has no setter 

     foreach (var pair in CustomerOrderDictionary) 
     { 
      if(pair.Key.Id==1) 
      { 
       pair.Value = 4;///ERROR HERE 
      } 
     } 
    } 
} 


public class Customer 
{ 
    public int Id { get; set; } 
    public string FullName { get; set; } 
} 

Toutes les suggestions? Merci beaucoup

Répondre

8

Je vous suggère de travailler sur les clés doivent modifier premier, puis itérer sur ces modifications. Sinon, vous finirez par modifier une collection pendant que vous l'itérez, ce qui créera une exception. Ainsi, par exemple:

// The ToList() call here is important, so that we evaluate all of the query 
// *before* we start modifying the dictionary 
var keysToModify = CustomerOrderDictionary.Keys 
              .Where(k => k.Id == 1) 
              .ToList(); 
foreach (var key in keysToModify) 
{ 
    CustomerOrderDictionary[key] = 4; 
} 
+0

Salut, Merci beaucoup qui a travaillé.J'essaierai de voir si cela fonctionne avec le vrai code.thanks – user9969

6

Le problème ici est que la paire est tapée KeyValuePair qui est un objet en lecture seule et ne peut pas être modifié. De plus, la collection KeyValuePair est un moyen d'afficher le contenu du dictionnaire (ne pas changer).

Ce que vous voulez faire ici est de modifier directement le dictionnaire. Le Key dans le KeyValuePair peut être utilisé pour mettre à jour la même entrée dans le dictionnaire.

if(pair.Key.Id==1) { 
    CustomerOrderDictionary[pair.Key] = 4; 
} 

EDIT

Comme le souligne Jon la cession annulera la iterator. L'itinéraire le plus simple, mais inefficace, consiste à copier l'énumérateur au début de la boucle.

foreach (var pair in CustomerOrderDictionary.ToList()) 
+2

Sauf que modifier le dictionnaire valide l'itérateur :( –

+0

salut, merci pour votre réponse. essayé par doest ne fonctionne pas.Est-ce que vous mettez le ci-dessus dans une boucle? sinon, quelle est la paire? désolé d'être idiot ici – user9969

+0

@Jon oh, oui, j'ai oublié cette partie. – JaredPar

0
foreach (Customer customer in customers.Keys) 
{ 
    if (customer.Id == 1) 
     customers[ customer ] = 4; 
} 
0
CustomerOrderDictionary[1] = 4; 
+0

C'est faux, la clé du dictionnaire n'est pas un int (voir ma réponse ..) –

0

est ici une façon de le faire (juste l'affectation d'une partie de la valeur ..):

CustomerOrderDictionary[new Customer { Id = 1, FullName = "Jo Bloogs" }]=4 

Notez que "1" est pas une clé dans votre dictionnaire. est Customer, vous devrez donc l'utiliser.

Notez également que Customer devrait mettre en œuvre IEquatable comme expliqué here

0

Ok, dans votre exemple, vous êtes effectivement juste de trouver l'entrée de l'objet Customer avec Id = 1 et mettre à jour la valeur associée. En pratique, je pense que votre code sera probablement en mesure d'obtenir une référence à votre objet Customer avant de mettre à jour la valeur associée dans le dictionnaire. Si tel est le cas, alors il n'y a pas besoin d'une boucle. Voici un exemple très simple où une boucle n'est pas nécessaire parce que votre code contient déjà une référence à la variable customer1. Bien que mon exemple soit trop simplifié, le concept est que vous pourriez potentiellement obtenir une référence à l'objet Customer souhaité par d'autres moyens que l'itération sur le dictionnaire.

static void Main(string[] args) 
    { 
     Dictionary<Customer, int> CustomerOrderDictionary = new Dictionary<Customer, int>(); 

     Customer customer1 = new Customer { Id = 1, FullName = "Jo Bloogs" }; 
     Customer customer2 = new Customer { Id = 2, FullName = "Rob Smith" }; 

     CustomerOrderDictionary.Add(customer1, 3); 

     CustomerOrderDictionary.Add(customer2, 5); 

     // you already have a reference to customer1, so just use the accessor on the dictionary to update the value 
     CustomerOrderDictionary[customer1]++; 
    } 

Si vous devez effectuer une sorte de mise à jour sur plusieurs Customer objets en fonction d'autres critères, alors vous pourriez avoir besoin d'une boucle. L'exemple suivant suppose que vous disposerez d'une collection autre que le dictionnaire qui stocke vos objets Customer et que vous pouvez utiliser cette collection d'objets Customer pour identifier ceux dont la valeur associée dans le dictionnaire doit être mise à jour.

static void Main(string[] args) 
    { 
     // presumably you will have a separate collection of all your Customer objects somewhere 
     List<Customer> customers = new List<Customer>(); 

     Customer customer1 = new Customer { Id = 1, FullName = "Jo Bloogs" }; 
     Customer customer2 = new Customer { Id = 2, FullName = "Rob Smith" }; 
     Customer customer3 = new Customer { Id = 3, FullName = "Rob Zombie" }; 

     customers.Add(customer1); 
     customers.Add(customer2); 
     customers.Add(customer3); 

     Dictionary<Customer, int> CustomerOrderDictionary = new Dictionary<Customer, int>(); 

     CustomerOrderDictionary.Add(customer1, 3); 
     CustomerOrderDictionary.Add(customer2, 5); 

     // let's just say that we're going to update the value for any customers whose name starts with "Rob" 
     // use the separate list of Customer objects for the iteration, 
     // because you would not be allowed to modify the dictionary if you iterate over the dictionary directly 
     foreach (var customer in customers.Where(c => c.FullName.StartsWith("Rob"))) 
     { 
      // the dictionary may or may not contain an entry for every Customer in the list, so use TryGetValue 
      int value; 
      if (CustomerOrderDictionary.TryGetValue(customer, out value)) 
       // if an entry is found for this customer, then increment the value of that entry by 1 
       CustomerOrderDictionary[customer] = value + 1; 
      else 
       // if there is no entry in the dictionary for this Customer, let's add one just for the heck of it 
       CustomerOrderDictionary.Add(customer, 1); 
     } 
    } 

Si ce n'est pas le cas et la seule source de Customer objets dont vous disposez est le dictionnaire lui-même, alors vous aurez besoin d'effectuer une sorte de clonage/copie de ces objets à une liste séparée/array avant d'itérer sur le dictionnaire pour une modification. Voir la réponse de Jon Skeet pour cette affaire; il suggère d'utiliser un filtre Where sur la propriété Keys du dictionnaire et utilise la méthode ToList pour créer une instance distincte List<Customer> à des fins d'itération.

1

Voici une autre approche

1) Créer une nouvelle classe

// wrapper class to allow me to edit a dictionary 
public class IntWrapper 
{ 
    public int OrderCount{ get; set; } 
} 

2) Modifier cette déclaration

Dictionary<Customer, IntWrapper> CustomerOrderDictionary = new Dictionary<Customer, IntWrapper>(); 

3) Assigner votre variable

pair.Value.OrderCount = 4; 
+0

Pourquoi le vote négatif? Cela fonctionne pour moi ... un feedback constructif est apprécié – LamonteCristo

+0

Je viens de définir un 'Holder ' générique avec un seul champ 'Value', plutôt que de définir une classe pour envelopper particulièrement 'int'. En outre, vous avez oublié d'indiquer comment les nouveaux wrappers doivent être ajoutés au dictionnaire. – supercat

+0

Un avantage qui mérite d'être mentionné est que, lorsqu'il est utilisé dans des scénarios multi-threads libres, vous pouvez utiliser un 'ReaderWriterLockSlim' pour garder un dictionnaire, et seulement acquérir un verrou' Writer' lorsque vous changez le dictionnaire lui-même. Lorsque vous travaillez avec un élément, vous pouvez acquérir un verrou sur l'élément, mais cela n'interférera pas avec l'accès des autres au dictionnaire. – supercat

Questions connexes