Делить объекты между классами в C # - PullRequest
2 голосов
/ 20 марта 2019

Я хочу, чтобы один объект разделялся двумя классами, если они имеют одинаковый ключ (это просто строка), поэтому, если значение объекта изменяется, оно изменяется в обоих классах. Я думаю, что это будет как если бы два объекта указывали на один и тот же адрес памяти, поэтому в Си это можно сделать с помощью указателей. Чтобы уточнить, что я хочу сделать, я подготовил следующий пример кода:

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

Обратите внимание, что параметр secondClass по-прежнему указывает на 0, значение не было обновлено. Это можно сделать в C #? Может быть, поделиться ссылкой?

--- РЕДАКТИРОВАТЬ ---

Теперь я включил минимальный, полный и проверяемый пример, как просил Джон Скит.

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

    }
}

Как видите, объект secondClass.parameter не изменился и все еще указывает на исходный. Конечно, если бы это был только один объект, я мог бы добавить в конце эти две строки:

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

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

Есть две основные проблемы:

  • MyObject является более сложным, чем показанный здесь, с более атрибуты внутри.

  • MainClass и SecondaryClass имеют несколько объектов MyObject, и для совместного использования необходимы только объекты с одинаковым ключом (и оба класса могут иметь объекты MyObject, не являющиеся общими). ​​

Ответы [ 3 ]

2 голосов
/ 20 марта 2019

При parameter = newParameter вы изменяете только ссылку на MyObject parameter, которая является локальной переменной. Вы не изменяете ссылку на свой объект в списке secondClass.

1 голос
/ 21 марта 2019

Вы пытались сделать класс MyObject синглтоном? Затем вы можете использовать любой класс структуры данных, такой как HashTable. Я предлагаю использовать Hashtable потому, что он безопасен для потоков.

0 голосов
/ 20 марта 2019

Причина проблемы описана С. Шенкелем: вы просто переназначаете локальную переменную с помощью своего текущего псевдокода.

Если вы хотите обновить фактический объект, «указанный», вы могли бы, дляНапример, выполните следующие действия, чтобы получить доступ к реальному объекту и изменить фактическое поле интереса:

Вы можете получить доступ к фактическому объекту, например, так:

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

Однако вы должны сделать value открытое поле или свойство с общедоступным сеттером, чтобы иметь возможность сделать это.


Конечно, это просто чтобы дать вам идею.

Вероятно, вы должны сделать что-то более понятное / лучше инкапсулированное, как это:

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

Обратите внимание, что теперь вы можете отложить бремя поиска, если ключ существует в этом методе "UpdateParameter".

Ваш «основной» код может стать следующим:

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

Примечание: я не понимаю идею использования «списка» параметров, в дополнение к наличию поля, хранящего один параметр.

Как предполагается, если у вас есть несколько пар ключ-значение, вы должны использовать Dictionary<string, MyObject> в качестве внутреннего поля вашего MainClass и SecondaryClass, что значительно упростит доступ и читаемость вашего кода.

...