如何通过变量修改List中的对象?C#引用赋值问题问询
问题分析与解决方案
首先咱们得搞明白为什么你的代码执行后输出false——这是C#引用类型变量的工作逻辑导致的:
当你执行Foo f = list[0];时,变量f和list[0]都指向同一个对象实例f1,但它们是两个独立的引用变量。当你给f赋值f2时,只是把f的指向改成了f2,但list[0]的指向依然是f1,所以最后比较自然是false。
你完全不需要用指针来实现“通过修改f改变list[0]”的需求,C#有更安全、更符合托管代码风格的方式,下面分场景给你方案:
场景1:修改对象的成员(而非替换整个对象)
如果你的目标是修改list[0]指向对象的属性/字段,而非把它换成另一个对象,那直接操作f的成员就可以了——因为f和list[0]指向同一个实例:
public class Foo { public string Name { get; set; } } // 测试代码 Foo f1 = new Foo { Name = "Old" }; Foo f2 = new Foo { Name = "New" }; List<Foo> list = new List<Foo>() { f1 }; Foo f = list[0]; f.Name = f2.Name; // 修改f指向对象的成员 Console.WriteLine(list[0].Name); // 输出"New",list[0]的对象已被修改
场景2:替换list[0]指向的整个对象
如果你确实需要把list[0]换成f2,可以用以下两种优雅的方式:
方式1:使用引用参数(ref)
写一个接收ref参数的方法,通过它直接修改列表元素的引用:
void ReplaceFoo(ref Foo target, Foo newInstance) { target = newInstance; } // 调用方法替换list[0] ReplaceFoo(ref list[0], f2); Console.WriteLine(list[0] == f2); // 输出true
方式2:使用包装类
把Foo实例包装在一个容器类里,列表存储容器的引用,修改容器内的值就会同步到列表中:
public class Wrapper<T> { public T Value { get; set; } } // 测试代码 Wrapper<Foo> w1 = new Wrapper<Foo> { Value = f1 }; Wrapper<Foo> w2 = new Wrapper<Foo> { Value = f2 }; List<Wrapper<Foo>> list = new List<Wrapper<Foo>> { w1 }; Wrapper<Foo> w = list[0]; w.Value = f2; // 修改包装类的Value属性 Console.WriteLine(list[0].Value == f2); // 输出true
关于指针的选项(不推荐)
虽然C#支持unsafe代码和指针,但这是非常不推荐的方式——它违背了C#的托管内存安全模型,需要开启项目的unsafe编译选项,还容易引发内存问题。如果非要用指针,代码大概是这样:
unsafe { Foo f1 = new Foo(); Foo f2 = new Foo(); List<Foo> list = new List<Foo>() { f1 }; fixed (Foo* ptr = &list[0]) { *ptr = f2; // 通过指针直接修改列表元素的引用 } Console.WriteLine(list[0] == f2); // 输出true }
但再次强调:除非你在做极端性能优化的底层场景,否则完全没必要用这种方式,优先选择前面的安全方案。
内容的提问来源于stack exchange,提问作者Dmitry Goldrey
相关产品推荐
相关产品推荐

