提问人:Nick W. 提问时间:5/9/2019 更新时间:5/9/2019 访问量:1198
如何更新按值传递的引用类型的引用
How to update reference of reference-type passed by value
问:
我正在使用一个按值在类之间传递对象的框架,我需要更新对其中一个对象的引用。我可以很好地更改原始对象的属性值,但我似乎无法弄清楚如何更改对全新对象的引用。在后一个类中,我从 API 中检索一个相当复杂的对象,因此我希望只更新引用而不是尝试深度复制。
我尝试调用我的代码示例,但没有成功的迹象。输出始终为:SwapPerson{One,Two,Three,Four}
Main.person: Groucho Marx is 128 years old!
Main.person: Groucho Marx is 129 years old!
Main.person: Groucho Marx is 129 years old!
我希望有一个简单的解决方案,由于时间晚了,我忽略了它,所以任何意见都非常感谢。
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public override string ToString()
{
return $"{FirstName} {LastName} is {Age} years old!";
}
}
public class Foo
{
private Person person;
public Foo(Person person)
{
this.person = person;
}
public void SetAge(int age)
{
person.Age = age;
}
public void SwapPersonOne(Person newPerson)
{
person = newPerson;
}
public void SwapPersonTwo(ref Person newPerson)
{
person = newPerson;
}
public void SwapPersonThree(Person newPerson)
{
LocalSwap(ref person);
void LocalSwap(ref Person oldPerson)
{
oldPerson = newPerson;
}
}
public void SwapPersonFour(Person newPerson)
{
LocalSwap(ref person, ref newPerson);
void LocalSwap(ref Person oldPerson, ref Person _newPerson)
{
oldPerson = _newPerson;
}
}
}
static void Main(string[] args)
{
Person person = new Person { FirstName = "Groucho", LastName = "Marx", Age = 128 };
Console.WriteLine($"{nameof(Main)}.{nameof(person)}: {person}");
var foo = new Foo(person);
foo.SetAge(129);
Console.WriteLine($"{nameof(Main)}.{nameof(person)}: {person}");
var charlie = new Person { FirstName = "Charlie", LastName = "Chaplin", Age = 130 };
//foo.SwapPersonOne(charlie);
//foo.SwapPersonTwo(ref charlie);
//foo.SwapPersonThree(charlie);
foo.SwapPersonFour(charlie);
Console.WriteLine($"{nameof(Main)}.{nameof(person)}: {person}");
Console.ReadLine();
}
答:
您在内部局部函数中使用关键字,但不在外部函数中使用关键字。此外,如果意图实际上是交换引用,则该方法不会按原样执行此操作。ref
public void SwapPersonFour(Person newPerson)
{
LocalSwap(ref person, ref newPerson);
void LocalSwap(ref Person oldPerson, ref Person _newPerson)
{
oldPerson = _newPerson;
}
}
oldPerson
并通过引用传递给本地函数,但通过值传递。_newPerson
newPerson
SwapPersonFour
另外,只有更新,所以现在两者都引用相同的.oldPerson
oldPerson
_newPerson
Person
如果要更新传递给的引用,还必须使用关键字通过引用传递该参数。SwapPersonFour
ref
public void SwapPersonFour(ref Person newPerson)
评论提到它不起作用,所以我匆忙地进行了单元测试,看看我是否遗漏了什么。(我总是想念一些东西,这就是我写单元测试的原因。
[TestClass]
public class UnitTest1
{
private Person _person;
[TestMethod]
public void TestSwappingPerson()
{
_person = new Person { FirstName = "Scott" };
var newPerson = new Person() { FirstName = "Bob" };
SwapPersonFour(ref newPerson);
Assert.AreEqual("Bob", _person.FirstName);
}
public void SwapPersonFour(ref Person newPerson)
{
LocalSwap(ref _person, ref newPerson);
void LocalSwap(ref Person oldPerson, ref Person localNewPerson)
{
oldPerson = localNewPerson;
}
}
}
SwapPersonFour
将该字段替换为对 的引用。它实际上并没有交换任何东西,因为当它更新时,它并没有更新。完成后,它们都是对同一 .(你是想交换它们吗?这可能是问题所在。_person
newPerson
_person
newPerson
Person
就其价值而言,我会删除本地函数,因为它实际上没有任何作用。它只接受该方法执行的一件事,并将其嵌套在一个额外的函数中。你可以用它替换它并得到相同的结果 - 它只是更容易阅读。(事实上,额外的代码可能更容易错过任何交换。我不了解你,但不需要太多让我感到困惑。
public void SwapPersonFour(ref Person newPerson)
{
_person = newPerson;
}
如果你真的想交换它们,那么你可以这样做:
public void SwapPersonFour(ref Person newPerson)
{
var temp = _person;
_person = newPerson;
newPerson = temp;
}
评论
ref
_name
_name
_person
UnitTest1
评论
ref
ref
Foo(ref T y)
Foo(ref x)
x
y
ref
SwapPersonTwo
SwapPersonOne