For classes,这实际上没有任何区别;你总是只处理一个引用和该引用的偏移量。传递参考是非常便宜的。
When it does开始重要的是structs。请注意,这不会影响调用类型上的方法- 通常这是基于引用的静态调用;但是当结构是一个参数对于方法来说,这很重要。
(编辑:实际上,在结构上调用方法时也很重要if你通过装箱操作来调用它们,因为盒子也是一个副本;这是避免盒装电话的一个重要原因!)
免责声明:你probably不应该经常使用结构。
对于结构体,该值占用那么多空间无论何时将其用作值,它可以是一个字段、堆栈上的局部变量、范围到方法等。这也意味着copying结构(例如,作为参数传递)可能会很昂贵。但如果我们举个例子:
struct MyBigStruct {
// lots of fields here
}
void Foo() {
MyBigStruct x = ...
Bar(x);
}
void Bar(MyBigStruct s) {...}
然后当我们打电话时Bar(x)
, we copy堆栈上的结构。同样,每当本地用于存储时(假设它没有被编译器删除):
MyBigStruct x = ...
MyBigStruct asCopy = x;
但!我们可以通过传递一个来解决这些问题参考周围代替。在当前版本的 C# 中,最合适的做法是使用in
, ref readonly
, and readonly struct
:
readonly struct MyBigStruct {
// lots of readonly fields here
}
void Foo() {
MyBigStruct x = ...
Bar(x); // note that "in" is implicit when needed, unlike "ref" or "out"
ref readonly MyBigStruct asRef = ref x;
}
void Bar(in MyBigStruct s) {...}
现在有zero实际副本。这里的所有内容都涉及对原始内容的引用x
。事实确实如此readonly
意味着运行时知道它可以信任in
参数上的声明,而不需要值的防御性副本。
具有讽刺意味的是,也许:添加in
参数上的修饰符可以介绍如果输入类型是 a 则复制struct
未标记的readonly
,因为编译器和运行时需要保证内部所做的更改Bar
调用者将看不到。这些更改不必是显而易见的 - 如果类型是邪恶的,任何方法调用(包括属性获取器和一些运算符)都可以改变值。举个邪恶的例子:
struct Evil
{
private int _count;
public int Count => _count++;
}
编译器和运行时的工作是按可预测的方式工作even if你是邪恶的,因此它添加了结构的防御副本。与相同的代码readonly
结构体上的修饰符不会编译.
你也可以做类似的事情in
with ref
如果类型不是readonly
,但是你需要意识到如果Bar
改变值(故意或作为副作用),这些变化将是可见的Foo
.