2013-07-10 25 views
0

我正在寻找一种集合的类型/方法,我可以将一个对象添加到一组对象中,然后分别更改该对象的属性,并且这些更改反映在集合中的对象中。创建对象的原始引用的抓包(集合)

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

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

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

我希望'valuesList'包含新值“Bravo”。试过了,我意识到列表拷贝的参考,它不吸收它,所以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。)

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

UPDATE

正如答案和评论中指出的那样,业务需求模型和干运行示例之间存在一些差异。我会将这个生命课程压缩成这样:看起来List<objects>跟踪了他们的变化,而List<values>没有。

+0

你没有在你的第一个例子“更改对象的属性”,你只是改变一个局部变量来指代不同的对象。你对列表所做的描述(“参考文献应该是同一个对象”)是正确的。第二个例子应该工作得很好,你试过了吗? – delnan

+0

您的代码将引用复制到列表中,然后创建新的引用。如果String类具有假设的“Content”属性,则initialValue.Content =“Bravo”也会更改列表中的字符串。但它没有一个,字符串是不可变的。将你自己班级的一个对象放入列表中,解决你的问题,这个班级具有这样一个Content属性。 –

+0

(facepalm)我只是用字符串测试行为的一般原理,但是你是对的,*对象*(类)的列表的确如其应该的那样工作。该死的,那很尴尬。不知道这是否仍然是一个有效的问题。 – RJB

回答

0

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

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

看来你的实际业务案例应该正常工作,除非它们被声明为结构。

+0

@nsinreal我的错误。由于它们的不变性,它们的行为类似于价值类型,所以我假设不查找它。事实证明,它们是通过引用传递的,因为它们可能对堆栈太大。 – TheEvilPenguin

+1

通过引用并不是您要查找的术语(我知道OP也是这样做的)。通过引用传递将使用'ref'或'out',这确实可以做类似于OP所期望的事情(例如'void Zero(ref int a){a = 0;}'确实会改变'Zero (ref x);')。 – delnan

+0

@delnan我知道“通过引用传递”是指使用'ref'关键字,但我的印象是它也引用了引用类型默认传递给方法的方式。是否还有另一个术语,或者我应该说这个类型是一个引用类型? – TheEvilPenguin

1

好吧。看起来你不明白发生了什么。这里有关于.net type internals的很棒的文章。

不久,在你的榜样情况与字符串的内容:

  1. 创建列表
  2. 创建字符串类型的变量初值。此变量的值存储在特殊的局部变量容器中。因为字符串是引用类型,所以它在作为指向对象的指针所包含的局部变量的容器中。
  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"); 
    } 
    
相关问题