我一直以为类类型的方法参数默认是作为引用参数传递的。显然情况并非总是如此。在 C# 中考虑这些单元测试(使用 MSTest)。
[TestClass]
public class Sandbox
{
private class TestRefClass
{
public int TestInt { get; set; }
}
private void TestDefaultMethod(TestRefClass testClass)
{
testClass.TestInt = 1;
}
private void TestAssignmentMethod(TestRefClass testClass)
{
testClass = new TestRefClass() { TestInt = 1 };
}
private void TestAssignmentRefMethod(ref TestRefClass testClass)
{
testClass = new TestRefClass() { TestInt = 1 };
}
[TestMethod]
public void DefaultTest()
{
var testObj = new TestRefClass() { TestInt = 0 };
TestDefaultMethod(testObj);
Assert.IsTrue(testObj.TestInt == 1);
}
[TestMethod]
public void AssignmentTest()
{
var testObj = new TestRefClass() { TestInt = 0 };
TestAssignmentMethod(testObj);
Assert.IsTrue(testObj.TestInt == 1);
}
[TestMethod]
public void AssignmentRefTest()
{
var testObj = new TestRefClass() { TestInt = 0 };
TestAssignmentRefMethod(ref testObj);
Assert.IsTrue(testObj.TestInt == 1);
}
}
结果是 AssignmentTest()
失败,其他两个测试方法通过。我认为问题是将新实例分配给 testClass
参数会破坏参数引用,但不知何故显式添加 ref
关键字可以修复此问题。
谁能详细解释这里发生的事情?我主要只是想扩展我对 C# 的了解;我没有要解决的任何特定场景...
最佳答案
几乎总是被遗忘的一件事是类不是按引用传递的,对类的引用是按值传递的。
这很重要。不是复制整个类(在刻板印象中按值传递),而是复制对该类的引用(我尽量避免说“指针”)。这是 4 或 8 个字节;比复制整个类更容易接受,实际上意味着该类是“通过引用”传递的。
此时,方法拥有自己的类引用副本。将引用 分配给方法内的范围(该方法仅重新分配它自己的引用副本)。
取消对该引用的引用(例如,与类成员交谈)将按您预期的方式工作:除非您将其更改为查看新实例(这就是您在失败测试中所做的),否则您会看到底层类).
使用 ref
关键字可以有效地通过引用(指向指针之类的指针)传递引用本身。
一如既往,Jon Skeet 提供了一篇写得很好的概述:
http://www.yoda.arachsys.com/csharp/parameters.html
注意“引用参数”部分:
Reference parameters don't pass the values of the variables used in the function member invocation - they use the variables themselves.
如果该方法将某些内容分配给 ref
引用,那么调用者的副本也会受到影响(正如您所观察到的),因为他们正在查看相同 引用内存中的一个实例(而不是每个实例都有自己的副本)。
关于c# - 在 C# 中将类作为 ref 参数传递并不总是按预期工作。谁能解释一下?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9996359/