创建对象的原始引用的抓包(集合)

时间:2013-07-10 22:51:37

标签: c# memory-management collections reference

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

我听说过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属性,我希望在'widgets'列表中反映出来。)

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

更新

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

2 个答案:

答案 0 :(得分:1)

好。看来你真的不明白发生了什么。这是关于.net type internals的精彩文章。

很快,您的示例中包含字符串会发生什么:

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

    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");
      }
      

答案 1 :(得分:0)

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

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

您的实际业务案例似乎应该正常运行,除非它们被声明为结构。