前言
最近在 dotnet/sdk 上看到一个 Issue,它提出了一个有趣的要求:默认情况下将类设置为密封类(Sealed)?
什么是密封类?
默认情况下,类是开放的,这意味着它是可以被继承的。例如:
class BaseClass
{public virtual string Method(){return "BaseClass.Method";}
}class DerivedClass : BaseClass
{public override string Method(){return "DerivedClass.Method";}
}class AnotherClass : DerivedClass
{//...
}
而密封类是一种特殊的类,它使用sealed
修饰符阻止其他类继承自该类。例如:
sealed class SealedClass : BaseClass
{public override string Method(){return "SealedClass.Method";}
}
那为什么要将类默认设为密封类呢?答案是——性能。
Benchmark
首先创建一个控制台程序,并添加 BenchmarkDotNet 包。
然后创建一个性能测试类:
public class PerformanceBenchmark
{private readonly DerivedClass derivedClass = new DerivedClass();private readonly SealedClass sealedClass = new SealedClass();[Benchmark]public void DerivedClass_Method() => derivedClass.Method();[Benchmark]public void SealedClass_Method() => sealedClass.Method();
}
并且修改Program.cs
文件,添加如下代码:
static void Main(string[] args)
{var summary = BenchmarkRunner.Run<PerformanceBenchmark>();
}
最后,运行程序,查看结果:
dotnet run -c Release
可以看到,SealedClass_Method
方法执行得明显快很多。
原理
为什么密封类比普通类执行得快呢?让我们看看 JIT 生成的代码:
可以看到,当调用密封类中的重写方法时,是直接在密封类对象的内存地址上完成的。而当调用普通类中的重写方法时,却需要额外的mov
指令,这是因为普通类的内存地址是不确定的,需要先获取到对象的类型,然后再从对应类型中获取方法。
总结
在本文中,我们了解了密封类有更好的性能。也就是说,如果你的类不会被继承,那么请将它设置为密封类。
添加微信号【MyIO666】,邀你加入技术交流群