Ignacio
Ignacio

Reputation: 838

Share objects between classes in C#

I want to have one object shared by two classes if they have the same key (it is just a string), so if the value of the object changes it changes in both classes. I think that it will be like having the two objects pointing to the same memory address, so in C it could be done with pointers. To clarify what I want to do I have prepared the next example code:

class MyObject
{
    string key;
    int value;

    public MyObject(string key, int value)
    {
        this.key = key;
        this.value = value;
    }
}

class MainClass{

    MyObject parameter = new MyObject("key", 5);
    List<MyObject> list = new List<MyObject>();
    list.Add(parameter);

}

class SecondaryClass{

    MyObject parameter = new MyObject("key", 0);
    List<MyObject> list = new List<MyObject>();
    list.Add(parameter);
}

MainClass mainClass = new MainClass();
SecondaryClass secondaryClass = new SecondaryClass();

foreach (MyObject newParameter in mainClass.list)
{
    // Try to find a match in the parameterKey
    MyObject parameter = secondaryClass.list.Find(p => p.Key == newParameter.Key);

    // If there is a match, update the object
    if (parameter != null)
    {
        parameter = newParameter;
    }
}

Console.WriteLine(mainClass.parameter.value) // This output 5

Console.WriteLine(secondaryClass.parameter.value) // This output 0

See that the parameter of the secondaryClass still points to 0, the value has not been updated. It is possible to do this in C#? Maybe sharing the reference?

--- EDIT ---

I include now a Minimal, Complete, and Verifiable example as Jon Skeet requested.

class MyObject
{
    public string key;
    public int value;

    public MyObject(string key, int value)
    {
        this.key = key;
        this.value = value;
    }
}

class MainClass
{

    public MyObject parameter = new MyObject("key", 5);
    public List<MyObject> list = new List<MyObject>();

    public MainClass()
    {
        list.Add(parameter);
    }
}

class SecondaryClass
{

    public MyObject parameter = new MyObject("key", 0);
    public List<MyObject> list = new List<MyObject>();

    public SecondaryClass()
    {
        list.Add(parameter);
    }
}

class Program
{
    static void Main(string[] args)
    {
        MainClass mainClass = new MainClass();
        SecondaryClass secondaryClass = new SecondaryClass();

        foreach (MyObject newParameter in mainClass.list)
        {
            // Try to find a match in the parameterKey
            MyObject parameter = secondaryClass.list.Find(p => p.key == newParameter.key);

            // If there is a match, update the object
            if (parameter != null)
            {
                parameter = newParameter;
            }
        }

        Console.WriteLine(mainClass.parameter.value); // This output 5
        Console.WriteLine(secondaryClass.parameter.value); // This output 0, I expected 5

        mainClass.parameter.value = 7;
        Console.WriteLine(mainClass.parameter.value); // This output 7
        Console.WriteLine(secondaryClass.parameter.value); // This output 0, I expected 7

    }
}

As you can see, the object secondaryClass.parameter is not changed and stills point to the original one. Of course, if it was only one object I could add at the end this two lines:

secondaryClass.parameter = mainClass.parameter;
mainClass.parameter.value = 9;

Console.WriteLine(mainClass.parameter.value); // This output 9
Console.WriteLine(secondaryClass.parameter.value); // This output 9

There are two main problems:

Upvotes: 2

Views: 3115

Answers (3)

parttimeadjunct
parttimeadjunct

Reputation: 24

Have you tried making MyObject class a singleton? Then you can utilize any data structure class such as a HashTable. Reason I suggest to use a Hashtable is because it's threadsafe.

Upvotes: 1

Pac0
Pac0

Reputation: 23174

Cause of the problem is described by S. Schenkel : you are merely reassigning the local variable with your current pseudo code.

If you want to update the actual object "referred to", you could, for instance, do the following to access the actual object and change the actual field of interest:

You could access the actual object like this for instance :

if (parameter != null)
{
    parameter.value = newParameter.value;
}

However you should make value a public field or a property with a public setter to be able to do that.


Of course, this is just to get you the idea.

Probably you should do something clearer / better encapsulated like this :

class SecondaryClass
{
    public MyObject parameter = new MyObject("key", 0);
    public List<MyObject> list = new List<MyObject>();

    public SecondaryClass()
    {
        list.Add(parameter);
    }

    public UpdateParameter(MyObject newParameter, string key) 
    {
        // here you can write code that can *directly* access your field or list.
        // you can, for instance, search for the object by key in the list, delete it from the list, and add `newParameter` to the list
        // and reassign "parameter" with this new object.
    }
}

Note that you can now defer the burden of searching if the key exist in this "UpdateParameter" method.

your "main" code could become this :

    foreach (MyObject newParameter in mainClass.list)
    {
        // Try to find a match, and update it in the parameterKey
        secondaryClass.UpdateParameter(newParameter);
    }

Note : I don't understand the idea of using a "list" of parameters, additionally to having a field storing a single parameter.

As suggested, if you have several key-value pairs, you should use a Dictionary<string, MyObject> as an internal field of your MainClass and SecondaryClass, that would simplify access and readability of your code a lot.

Upvotes: 0

S. Schenkel
S. Schenkel

Reputation: 191

With parameter = newParameter, your are only modifying the reference of MyObject parameter which is a local variable. You are not modifying the reference of your object in the list of secondaryClass.

Upvotes: 2

Related Questions