1

Background

I understand a C# dictionary is a data structure that represents a collection of key|value pairs.

The below code (LINQPad C# Program) and subsequent output screenshot demonstrates how I am attempting to use a dictionary to (1) retain the most recent two instances of a class (RefInteger) in order of creation, and (2) allow for the "deletion" of the most recent RefInteger instance. Where :

  • refDict[A] returns the most recent created instance of RefInteger,
  • refDict[B] returns the second most recent created instance, and
  • refDict[C] is only required to "resupply" refDict[B] in the event of the most recent RefInteger instance is "deleted" (via the RegressEntries method).

Code:

public enum Pos { A, B, C }
public Dictionary<Pos, RefInteger> refDict = new Dictionary<Pos, RefInteger>(); 

void Main()
{
    Create(1);
    refDict.Dump("Create 1");
    Create(2);
    refDict.Dump("Create 2");
    Create(3);
    refDict.Dump("Create 3");
    RegressEntries();
    refDict.Dump("Regress");
    Create(4);  
    refDict.Dump("Create 4");
    Create(5);  
    refDict.Dump("Create 5");
}

private void Create(int value)
{
    ProgressEntries();
    refDict[Pos.A] = new RefInteger(value); 
}

private void ProgressEntries()
{
    if (refDict.ContainsKey(Pos.B))
        refDict[Pos.C] = refDict[Pos.B];
    if (refDict.ContainsKey(Pos.A))
        refDict[Pos.B] = refDict[Pos.A];
}

private void RegressEntries()
{
    if (refDict.ContainsKey(Pos.B))
        refDict[Pos.A] = refDict[Pos.B];
    if (refDict.ContainsKey(Pos.C))
        refDict[Pos.B] = refDict[Pos.C];
}

public class RefInteger
{
  public int Value;

  public RefInteger(int value)
  {
      Value = value;
  }
}

Screenshot

LINQPad Output

Question

While the above simplified example behaves as I expect a dictionary to behave, I have dictionary where the ProgressEntries method appears to result in each subsequent refDictkey pointing to the most recent value. It would be the equivalent of receiving the below output from the simplified example:

enter image description here

Please suggest how this is possible.

Noting, I have confirmed the order of "progression" within the ProgressEntries method is correct (i.e. move refDict[B] to refDict[C] THEN move refDict[A] to refDict[B]).
The problem dictionary while small, uses a composite key to return values. Moving to another structure is not really an option.
The example code uses a simple class (refInteger) as opposed to a primitive type to ensure my understanding of dictionary behavior is correct.

Thanks

Shannon

EDIT: Please find below the requested example console app code. The example behaves as expected. I will keep digging into the issue with the actual code.

using System;
using System.Collections.Generic;

namespace DictionaryProgress
{
    class Program
    {
        public enum Pos { A, B, C }

        static void Main()
        {
            var refDictionary = new RefDictionary();
            refDictionary.Update();
            Console.ReadKey();
        }

        public class RefDictionary
        {
            public Dictionary<Pos, RefInteger> RefDict = new Dictionary<Pos, RefInteger>();

            public void Update()
            {
                Create(1);
                Console.WriteLine("Create 1 : {0}", ToString());
                Create(2);
                Console.WriteLine("Create 2 : {0}", ToString());
                Create(3);
                Console.WriteLine("Create 3 : {0}", ToString());

                RegressEntries();
                Console.WriteLine("Regress  : {0}", ToString());
                Create(4);
                Console.WriteLine("Create 4 : {0}", ToString());
                Create(5);
                Console.WriteLine("Create 5 : {0}", ToString());
            }

            private void Create(int value)
            {
                ProgressEntries();
                RefDict[Pos.A] = new RefInteger(value);
            }

            private void ProgressEntries()
            {
                if (RefDict.ContainsKey(Pos.B))
                    RefDict[Pos.C] = RefDict[Pos.B];
                if (RefDict.ContainsKey(Pos.A))
                    RefDict[Pos.B] = RefDict[Pos.A];
            }

            private void RegressEntries()
            {
                if (RefDict.ContainsKey(Pos.B))
                    RefDict[Pos.A] = RefDict[Pos.B];
                if (RefDict.ContainsKey(Pos.C))
                    RefDict[Pos.B] = RefDict[Pos.C];
            }

            public override string ToString()
            {
                var PosA = RefDict.ContainsKey(Pos.A) ? 
                    RefDict[Pos.A].Value : 0;
                var PosB = RefDict.ContainsKey(Pos.B) ?
                    RefDict[Pos.B].Value : 0;
                var PosC = RefDict.ContainsKey(Pos.C) ? 
                    RefDict[Pos.C].Value : 0;

                return string.Format("{0}, {1}, {2}", PosA, PosB, PosC);
            }
        }

        public class RefInteger
        {
            public int Value;

            public RefInteger(int value)
            {
                Value = value;
            }
        }            

    }
}
4
  • 4
    It would be really helpful if you'd just provide a short but complete console app that demonstrates the problem. In particular, you say that the code you've shown does work, but then you've got other code which doesn't... it's hard to debug code we can't see. Commented Mar 2, 2015 at 10:41
  • 1
    I'm really not sure that a dictionary is the appropriate data structure for this task. It feels like a job for a stack (with a peek function so you can see the most recent going backwards without popping) or a deque if you want to limit the size of the "list" of numbers. Commented Mar 2, 2015 at 10:43
  • @JonSkeet I will work towards providing a console app. Commented Mar 2, 2015 at 10:53
  • 1
    While I agree with @JeffWatkins that Dictionary seems to be poorly-suited to your problem, I'm not sure you need any kind of standard collection (stack, etc.) To me it sounds like something that could be handled with three variables (each containing a key and value variable) and a few lines of C# code. Commented Mar 2, 2015 at 11:31

1 Answer 1

1

As commenter Jon Skeet has suggested, if you want help with code that doesn't work, the code you post in your question should be that code. Showing us code that does work, but then asking us to explain why some other code doesn't work isn't a very good way to get an answer.

That said, assuming the code that doesn't work is even remotely like the code that does work, I would say that the most obvious explanation for the behavior you are seeing is that the broken version of the code is not creating a new instance of the value object, but rather just reusing a previously-created instance.

That is, the described behavior shows a classic "reference-type copy" symptom.

Note that in the code that does work, you create a whole new instance of the value object when it's added to the dictionary:

RefDict[Pos.A] = new RefInteger(value);

I would bet that in the code that doesn't work, instead of assigning new ...something... as the value, you're assigning a reference to some other object.

Of course, without a good, minimal, complete code example showing the version of the code that doesn't work, it's not possible to know for sure what's wrong with it. So if the above doesn't explain for you why the code that doesn't work is behaving incorrectly, you should edit your question to include a proper code example.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.