在 C# 中的类之间共享对象

Posted

技术标签:

【中文标题】在 C# 中的类之间共享对象【英文标题】:Share objects between classes in C# 【发布时间】:2019-08-11 04:30:28 【问题描述】:

如果两个类具有相同的键(它只是一个字符串),我希望它们共享一个对象,因此如果对象的值发生变化,它会在两个类中发生变化。我认为这就像让两个对象指向相同的内存地址一样,所以在 C 中可以用指针来完成。为了阐明我想要做什么,我准备了下一个示例代码:

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

看到secondaryClass的参数还是指向0,值没有更新。可以在 C# 中执行此操作吗?也许分享参考?

--- 编辑 ---

我现在按照 Jon Skeet 的要求提供了一个最小、完整和可验证的示例。

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

    

如您所见,对象secondaryClass.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 对象)。

【问题讨论】:

只是快速阅读,这不是答案,但仅供参考,所有对象(类)变量都持有对 C# 中对象的 referencevar a = new Something(); var b = a; // now b refers to the *exact same object as a* in memory(如果 Something 是一个类)。顺便说一句,类也被称为引用类型,原因相同。 @Pac0 是的,我预料到了,但事实并非如此。 很难准确理解您要查找的内容,因为您只发布了伪代码。请提供minimal reproducible example。 使用字典太容易了。 @JonSkeet 完成了,下次我会从头开始这样做 【参考方案1】:

使用parameter = newParameter,您只需修改MyObject parameter 的引用,这是一个局部变量。 您没有在 secondaryClass 列表中修改对象的引用。

【讨论】:

这正是造成混乱的原因。【参考方案2】:

S. Schenkel 描述了问题的原因:您只是用当前的伪代码重新分配了局部变量。

如果您想更新“引用”的实际对象,例如,您可以执行以下操作来访问实际对象并更改实际感兴趣的字段:

例如,您可以像这样访问实际对象:

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&lt;string, MyObject&gt; 作为 MainClass 和 SecondaryClass 的内部字段,这将大大简化代码的访问和可读性。

【讨论】:

那只会更新值,而不是对象本身。我已经包含了新代码,可以看出在最后几行中我希望两个对象是相同的。 @Ignacio :您必须创建一些代码来执行更新,例如 SecondaryClass 的方法。为了更好地理解:您有一个引用对象的字段。在其他地方,您有对同一对象的引用。如果您通过重新分配变量来更改后一个引用,就像您所做的那样,这不会更改该字段最初引用的对象。这只是更改本地后一个引用。 我真的不知道如何处理您以某种方式对参数有两个引用的事实:一个在“参数”字段中,另一个在您的列表中。真的有必要吗? 问题是有一个 MainClass 有许多 MyObject(比示例更复杂,有更多东西)和其他几个共享对象的类(SecondaryClass、SecondaryClass2 等)。如果我更改一个对象 SecondaryClass 中的 myObjects 之一的值,我希望该更改传播到 MainClass、SecondaryClass2 等的其他对象。 嗯,这很复杂,如您所见。也许这超出了堆栈溢出问题的范围。也许最好的方法是解释你想要达到的目标,你的最终目标。这对我来说就像XY problem。也许你的整体架构可以改进和简化很多,但我们需要知道你的规格,你想要实现什么。【参考方案3】:

您是否尝试过将 MyObject 类设为单例?然后您可以使用任何数据结构类,例如 HashTable。我建议使用 Hashtable 的原因是因为它是线程安全的。

【讨论】:

以上是关于在 C# 中的类之间共享对象的主要内容,如果未能解决你的问题,请参考以下文章

C# 将共享项目中的类与许多项目集成

C# 怎样实现两个窗体之间的数据共享?

C# 在应用程序之间共享实例

如何在 SwiftUI 中的类和视图之间共享数据

⑤创建型设计模式原型模式

如何在不同的类中使用 QNetworkAccessManager?类之间一般共享重要数据?