【发布时间】:2019-11-11 20:47:01
【问题描述】:
MutableSlab 和ImmutableSlab 实现之间的唯一区别是readonly 修饰符应用于handle 字段:
using System;
using System.Runtime.InteropServices;
public class Program
{
class MutableSlab : IDisposable
{
private GCHandle handle;
public MutableSlab()
{
this.handle = GCHandle.Alloc(new byte[256], GCHandleType.Pinned);
}
public bool IsAllocated => this.handle.IsAllocated;
public void Dispose()
{
this.handle.Free();
}
}
class ImmutableSlab : IDisposable
{
private readonly GCHandle handle;
public ImmutableSlab()
{
this.handle = GCHandle.Alloc(new byte[256], GCHandleType.Pinned);
}
public bool IsAllocated => this.handle.IsAllocated;
public void Dispose()
{
this.handle.Free();
}
}
public static void Main()
{
var mutableSlab = new MutableSlab();
var immutableSlab = new ImmutableSlab();
mutableSlab.Dispose();
immutableSlab.Dispose();
Console.WriteLine($"{nameof(mutableSlab)}.handle.IsAllocated = {mutableSlab.IsAllocated}");
Console.WriteLine($"{nameof(immutableSlab)}.handle.IsAllocated = {immutableSlab.IsAllocated}");
}
}
但它们会产生不同的结果:
mutableSlab.handle.IsAllocated = False
immutableSlab.handle.IsAllocated = True
GCHandle 是一个可变结构,当您复制它时,它的行为与 immutableSlab 的场景完全相同。
readonly 修饰符是否会创建字段的隐藏副本?这是否意味着它不仅仅是编译时检查?我找不到有关此行为的任何信息here。是否记录了这种行为?
【问题讨论】:
-
我不会将此作为答案发布,因为我不能 100% 确定 GC 的行为。但是不,readonly 关键字不会引入新字段。它按照它在锡上说的做。您观察到的行为可能是由于 GC 没有按照您的意愿行事。尝试运行 GC.Collect()。 GC 接受提示,通常不接受命令。
-
我现在正在写一个答案......但是对于那些没有耐心的人,这是我之前写的一篇博文:codeblog.jonskeet.uk/2014/07/16/…
-
通过只读字段的成员调用会创建一个副本。并不是有一个额外的字段 - 而是在调用之前复制了该字段。
-
请注意,Resharper 实际上对此发出了警告;对于
ImmutableSlab中的this.handle.Free();,它给出警告:“值类型的只读字段调用了不纯方法。”
标签: c# struct value-type readonly-attribute