2010-10-19 14 views
7

Ich habe Wörterbuch, das ist besiedelt und ich habe keine Kontrolle über.Wörterbuch ändern Wert ist möglich. Was ist der richtige Ansatz?

Ich muss den Wert ändern, wie kann ich das tun?

Ich habe zusammen ein noddy Beispiel stellen das Problem

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

Irgendwelche Vorschläge zu erklären? Vielen Dank

Antwort

8

Ich schlage vor, Sie arbeiten heraus, welche Tasten müssen ersten ändern, und dann über diese Änderungen durchlaufen. Andernfalls werden Sie eine Sammlung ändern, während Sie darüber iterieren, wodurch eine Ausnahme ausgelöst wird. So zum Beispiel:

// 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

Hallo, Vielen Dank, dass funktioniert hat.Ich werde versuchen, um zu sehen, ob das mit dem echten Code funktioniert.Dank – user9969

6

Das Problem hier ist, dass Paar KeyValuePair getippt wird, die ein schreibgeschütztes Objekt ist und nicht geändert werden kann. Zusätzlich ist die KeyValuePair Sammlung eine Möglichkeit, den Inhalt des Wörterbuchs anzuzeigen (ohne es zu ändern).

Was Sie hier tun möchten, ist nur das Wörterbuch direkt ändern. Die Key in der KeyValuePair kann verwendet werden, um den gleichen Eintrag im Wörterbuch zu aktualisieren.

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

EDIT

Wie Jon wies die Zuordnung aus dem Iterator ungültig machen. Die einfachste, aber ineffektive Methode besteht darin, den Enumerator am Anfang der Schleife zu kopieren.

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

Außer das Ändern des Wörterbuchs in validiert den Iterator :( –

+0

Hallo, vielen Dank für Ihre Antwort. versucht von doest nicht funktionieren.Stellen Sie das oben in eine Schleife? wenn nicht was ist Paar? Entschuldigung dafür, hier dumm zu sein – user9969

+0

@Jon oh, ja, vergaß diesen Teil. – JaredPar

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

Das ist falsch, der Schlüssel des Wörterbuchs ist kein int (siehe meine Antwort ..) –

0

Hier ist eine Art und Weise, dass (nur die Zuweisung ein Wert Teil ..) zu tun:

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

Beachten Sie, dass "1" kein Schlüssel im Wörterbuch ist. a Customer ist, so müssen Sie das verwenden.

Beachten Sie auch, dass Customer Sollte IEquatable implementieren als here erklärt

0

Ok, in Ihrem Beispiel sind Sie effektiv nur den Eintrag für das Customer Objekt zu finden, mit Id = 1 und dem zugehörigen Wert zu aktualisieren. In der Praxis glaube ich, dass Ihr Code wahrscheinlich einen Verweis auf Ihr beabsichtigtes Objekt erhalten wird, bevor der zugehörige Wert im Wörterbuch aktualisiert wird. Wenn dies der Fall ist, ist keine Schleife erforderlich.

Unten ist ein sehr einfaches Beispiel, in dem eine Schleife nicht benötigt wird, da Ihr Code bereits eine Referenz auf die customer1 Variable hat. Während mein Beispiel übermäßig vereinfacht ist, ist das Konzept, dass Sie möglicherweise eine Referenz auf Ihr gewünschtes Customer Objekt auf andere Weise als über das Wörterbuch iterieren können.

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]++; 
    } 

Wenn Sie eine Art von Update auf mehrere Customer Objekte basierend auf einigen anderen Kriterien erfüllen, dann könnten Sie eine Schleife benötigen. Im folgenden Beispiel wird davon ausgegangen, dass Sie eine andere Sammlung als das Wörterbuch haben, das Ihre Customer Objekte speichert, und dass Sie diese Sammlung von Customer Objekten verwenden können, um diejenigen zu identifizieren, deren zugehöriger Wert im Wörterbuch aktualisiert werden muss.

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

Ist dies nicht der Fall ist, und die einzige Quelle für Customer Objekte, die Sie zur Verfügung haben, ist das Wörterbuch selbst, dann müssen Sie eine Art von Klonen/Kopieren dieser Objekte, um eine separate Liste auszuführen/Array vor dem Iterieren über das Wörterbuch für die Änderung. Siehe Jon Skeets Antwort für diesen Fall; Er schlägt vor, einen Where Filter für die Eigenschaft Keys des Wörterbuchs zu verwenden und verwendet die ToList Methode, um eine separate List<Customer> Instanz für den Zweck der Iteration zu erstellen. Erstellen Sie hier

1

ist ein alternativer Ansatz

1) eine neue Klasse

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

2) Ändern sich diese Erklärung

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

3) Ordnen Sie Ihre Variable

pair.Value.OrderCount = 4; 
+0

Warum die negative Stimme? Es funktioniert für mich ... konstruktives Feedback wird geschätzt – LamonteCristo

+0

Ich definiere einfach ein generisches 'Holder ' mit einem einzelnen 'Value'-Feld, anstatt eine Klasse zu definieren, die speziell 'int' umschließt. Außerdem haben Sie vergessen zu zeigen, wie neue Wrapper zum Wörterbuch hinzugefügt werden sollen. – supercat

+0

Ein Vorteil, der erwähnenswert ist, ist, dass wenn Sie in Frei-Multi-Threaded-Szenarien verwenden, können Sie eine 'ReaderWriterLockSlim' verwenden, um ein Wörterbuch zu schützen, und nur eine' Writer' Sperre erwerben, wenn Sie das Wörterbuch selbst ändern. Wenn Sie mit einem Objekt arbeiten, möchten Sie möglicherweise eine Sperre für das Objekt erstellen, die jedoch den Zugriff anderer auf das Wörterbuch nicht beeinträchtigt. – supercat

Verwandte Themen