0

我正在寻找一种集合类型/方法,我可以将一个对象添加到一组对象中,然后单独更改该对象的属性,并将这些更改反映在集合中的对象中。

我听说 List<T> 通过引用添加值,所以我认为引用将指向同一个对象。换句话说,我假设:

List<string> valuesList = new List<string>();
string initialValue = "Alpha";
valuesList.Add(initialValue);

initialValue = "Bravo";
bool incorrectAssumption = (valuesList[0] == "Bravo");

我曾希望 'valuesList' 将包含新值“Bravo”。尝试了一下,我意识到 List复制了引用,它没有吸收它,所以 valueList 仍然只有“Alpha”值。有什么方法可以将集合用作它们包含的少数合法对象?

如果它有助于了解实际的业务需求......

List<BaseWidget> widgets = new List<BaseWidget>();

DerivedWidget specialWidget = new DerivedWidget();
DerivedWidget extraSpecialWidget = new DerivedWidget();

widgets.Add(specialWidget);
widgets.Add(extraSpecialWidget);

specialWidget.Run();
extraSpecialWidget.Run();

if (!widgets.Any(x => x.RunSuccessfully)) return false;

(其中 Run() 方法设置了 RunSuccessfully 属性,我希望将其反映在“小部件”列表中。)

==================================================== ===========================

更新

正如答案和评论中指出的那样,业务需求模型和试运行示例之间存在一些差异。我会把人生的教训浓缩成这个:似乎List<objects>他们的变化被跟踪了,而List<values>没有。

4

2 回答 2

1

好。看来你不明白到底发生了什么。这是关于.net 类型内部的好文章。

很快,在您的示例中使用字符串会发生什么:

  1. 您创建列表
  2. 您创建字符串类型的变量 initialValue。此变量的值存储在特殊的局部变量容器中。因为字符串是引用类型,所以在局部变量的容器中,它包含一个指向对象的指针。
  3. 您创建新字符串“Alpha”,将其存储在堆中,并将指针(指向此字符串)分配给本地变量。
  4. 然后您将对象添加到列表中。在您的列表中,此对象存储为指向某处的指针。
  5. 然后,您通过将局部变量“initialValue”分配给指向另一个字符串的指针来更改它的内容。所以,现在局部变量'initialValue'是一个指针,在列表中是另一个指针。

那么,解决方案呢?

  1. 将您的字符串包装到另一个类。像这样:

    class Wrapper<T> {
        public T Content {get;set;}
    
    public Wrapper(T content) {
        Content = content;
        }
    }
    

    用法:

    void Main()
    {
        var valuesList = new List<Wrapper<string>>();
        var initialValue = new Wrapper<string>("Alpha");
        valuesList.Add(initialValue);
    
        initialValue.Content = "Bravo";
    
        Console.WriteLine(valuesList[0].Content);
    }
    

    有点难看的语法。

  2. 使用clojures:

    void Main()
    {
        List<Func<string>> valuesList = new List<Func<string>>();
        string initialValue = "Alpha";
        valuesList.Add(() => initialValue);
    
        initialValue = "Bravo";
        Console.WriteLine(valuesList[0]() == "Bravo");
    }
    
于 2013-07-10T23:22:58.360 回答
0

所有对非值类型的引用都将通过引用传递,List<T>或者不传递。 然而,String 是一种值类型,并且总是按值传递。它们也是不可变的,所以每当你改变一个时,你实际上是在创建一个新的字符串。

对于您的示例,您可以创建一个包装器类型来包含您的字符串,并将其存储在您的List<T>.

除非将它们声明为结构,否则您的实际业务案例似乎应该正常工作。

于 2013-07-10T22:55:09.297 回答