通常我在struct和class之间选择不是因为内存问题而是因为类型的语义.我的一些值类型具有相当大的内存占用,有时太大而无法一直复制此数据.所以我想知道总是通过引用传递不可变值对象是不是一个好主意?由于对象是不可变的,因此不能通过引用接受它们的方法进行修改.通过参考传递时是否还有其他问题?
Jon*_*eet 14
我的一些值类型具有相当大的内存占用量
从实现的角度来看,这表明它们不应该是值类型.从"开发类库的设计指南","在类和结构之间选择 "部分:
除非类型具有以下所有特征,否则不要定义结构:
- 它逻辑上表示单个值,类似于基本类型(整数,双精度等).
- 它的实例大小小于16个字节.
- 这是不可改变的.
- 它不必经常装箱.
听起来你应该创建不可变的引用类型.在许多方面,他们最终会感觉像"价值对象"(想想字符串),但你不必担心传递它们的效率.
价值类型的"不变性"是一个略带流动的概念 - 它当然并不意味着使用ref是安全的:
// int is immutable, right?
int x = 5;
Foo(ref x);
Console.WriteLine(x); // Eek, prints 6...
...
void Foo(ref int y)
{
y = 6;
}
Run Code Online (Sandbox Code Playgroud)
我们不会改变价值的一部分 - 我们用x完全不同的价值取代整个价值.
在涉及引用类型时,不变性更容易思考 - 尽管如此,你可以拥有一个本身不会改变的对象,但可以引用可变对象......
Eri*_*ert 11
乔恩的回答当然是正确的; 我会添加它:当您在值类型上调用方法时,值类型已通过引用传递.例如:
struct S
{
int x;
public S(int x) { this.x = x; }
public void M() { Console.WriteLine(this.x); }
}
Run Code Online (Sandbox Code Playgroud)
方法M()在逻辑上与以下内容相同:
public static void M(ref S _this) { Console.WriteLine(_this.x); }
Run Code Online (Sandbox Code Playgroud)
每当在结构上调用实例方法时,我们都会将ref传递给作为调用接收者的变量.
那么如果接收器不是变量呢?然后将该值复制到用作接收器的临时变量中.如果价值很大,这可能是一个昂贵的副本!
值类型按值复制; 这就是为什么他们被称为价值类型.除非您计划非常小心地找到所有可能的昂贵副本并消除它们,否则我将遵循框架设计指南的建议:将结构保持在16字节以下,并按值传递它们.
我还要强调Jon是对的:通过引用传递结构意味着将引用传递给变量,并且变量可以更改.这就是为什么他们被称为"变量".C#中没有"const ref",就像C++中的那样; 即使值类型本身似乎是"不可变的",也不意味着持有它的变量是不可变的.你可以在这个人为但教育的例子中看到一个极端的例子:
struct S
{
readonly int x;
public S(int x) { this.x = x; }
public void M(ref S s)
{
Console.WriteLine(this.x);
s = new S(this.x + 1);
Console.WriteLine(this.x);
}
}
Run Code Online (Sandbox Code Playgroud)
M可以写出两个不同的数字吗?你会天真地认为结构是不可变的,因此x不能改变.但是s和this都是变量,变量可以改变:
S q = new S(1);
q.M(ref q);
Run Code Online (Sandbox Code Playgroud)
,打印1,2,因为this和s有两个参考点q,并没有什么阻止q更改; 它不是只读的.
简而言之:如果我有很多数据需要传递并且有很强的保证它是不可变的,那么我将使用类,而不是结构.如果您已经通过将其作为结构实际解决了已证实的性能问题,则仅在该场景中使用结构,请记住,大型结构可能非常昂贵.
| 归档时间: |
|
| 查看次数: |
1274 次 |
| 最近记录: |