开发者

Modify Dictionary Value is possible.What is the right approach?

I have dictionary that is populated and I have no control of.

I need to modify the value how can I do that?

I have put a noddy example together to explain the 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)
            {
        开发者_StackOverflow中文版        pair.Value = 4;///ERROR HERE
            }
        }
    }
}


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

Any suggestions? Thanks a lot


I suggest you work out which keys need modifying first, and then iterate over those modifications. Otherwise you'll end up modifying a collection while you're iterating over it, which will throw an exception. So for example:

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


The problem here is that pair is typed to KeyValuePair which is a readonly object and can't be modified. Additionally the KeyValuePair collection is a way of viewing the contents of the dictionary (not changing it).

What you want to do here is just modify the dictionary directly. The Key in the KeyValuePair can be used to update the same entry in the dictionary.

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

EDIT

As Jon pointed out the assignment will invalidate the iterator. The simplest, but ineffecient route, is to copy the enumerator at the start of the loop.

foreach (var pair in CustomerOrderDictionary.ToList())


Here is an alternate approach

1) Create a new class

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

2) Change this declaration

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

3) Assign your variable

 pair.Value.OrderCount = 4; 


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


CustomerOrderDictionary[1] = 4;


Here's one way to do that (just the assigning a value part..):

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

Notice that "1" is not a key in your dictionary. a Customer is, so you'll have to use that.

Notice also that Customer Should implement IEquatable as explained here


Ok, in your example you're effectively just finding the entry for the Customer object with Id = 1 and updating the associated value. In practice, I think that your code will likely be able to obtain a reference to your intended Customer object prior to updating the associated value in the dictionary. If that is the case, then there's no need for a loop.

Below is a very simple example where a loop is not needed because your code already has a reference to the customer1 variable. While my example is overly simplified, the concept is that you could potentially obtain a reference to your desired Customer object through some means other than iterating over the dictionary.

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

If you need to perform some kind of update on multiple Customer objects based on some other criteria, then you might need a loop. The following example assumes that you'll have some collection other than the dictionary that stores your Customer objects, and that you can use that collection of Customer objects to identify the ones whose associated value in the dictionary need to be updated.

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

If this is not the case and the only source of Customer objects that you have available is the dictionary itself, then you'll need to perform some kind of cloning/copying of those objects out to a separate list/array prior to iterating over the dictionary for modification. See Jon Skeet's answer for this case; he suggests using a Where filter on the dictionary's Keys property and uses the ToList method to create a separate List<Customer> instance for the purpose of iteration.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜