用BenchmarkDotNet看Property
属性——Property,由get,set访问器组成,这是C#使用度比较高的类成员。今天分几组对比测试,来看一下使用Property的性能。
被测试对象:
public class MyClass
{
private string _myProperty1 = DateTime.Now.ToString();
public string MyProperty1 { get { return _myProperty1; } }
public string MyProperty2 { get { return DateTime.Now.ToString(); } }
public string MyMethod()
{
return DateTime.Now.ToString();
}
}
调用测试方法统一如下:
BenchmarkRunner.Run();
第一组:构造实例化对象和方法内实例化对象,调用属性差多少
[MemoryDiagnoser]
public class TestProperty
{
private readonly MyClass _myClass;
public TestProperty()
{
_myClass = new MyClass();
}
[Benchmark]
public string PropertyA()
{
return _myClass.MyProperty1;
}
[Benchmark]
public string PropertyAExt()
{
var myClass = new MyClass();
return myClass.MyProperty1;
}
}
结果:差别很大,因为毕竟有一个new的过程,需要开销,同时也能理解,提交初始尽量初始化,多次调用时就开销变少了。

第二组:比较用字段属性和无字段属性的差别
[MemoryDiagnoser]
public class TestProperty
{
private readonly MyClass _myClass;
public TestProperty()
{
_myClass = new MyClass();
}
[Benchmark]
public string PropertyA()
{
return _myClass.MyProperty1;
}
[Benchmark]
public string PropertyAExt()
{
var myClass = new MyClass();
return myClass.MyProperty1;
}
[Benchmark]
public string PropertyB()
{
return _myClass.MyProperty2;
}
[Benchmark]
public string PropertyBExt()
{
var myClass = new MyClass();
return myClass.MyProperty2;
}
}
结果:这组结果显示,有字段的属性更快,因为当类实体化时,字段的值已经初始化完成,所以PropertyA要好于PropertyB,关于PropertyBExt,初始化字段+实例化对象,都占了300ns。

第三组:用反射访问属性与正常访问属性对比
[MemoryDiagnoser]
public class TestProperty
{
private readonly MyClass _myClass;
private readonly PropertyInfo _proinfo;
public TestProperty()
{
_myClass = new MyClass();
_proinfo = _myClass.GetType().GetProperty("MyProperty");
}
[Benchmark]
public string PropertyA()
{
return _myClass.MyProperty1;
}
[Benchmark]
public string PropertyAExt()
{
var myClass = new MyClass();
return myClass.MyProperty1;
}
[Benchmark]
public string PropertyB()
{
return _proinfo.GetValue(_myClass).ToString();
}
[Benchmark]
public string PropertyBExt()
{
var myClass = new MyClass();
var proinfo = myClass.GetType().GetProperty("MyProperty");
return proinfo.GetValue(myClass).ToString();
}
}
结果:反射调用肯定要比正常调用差一些,无可厚非,仅供参考

第四组:重点看一下代理的性能比较
[MemoryDiagnoser] public class TestProperty { private readonly MyClass _myClass; private readonly PropertyInfo _proinfo; private readonly Funcstring > _delegate; public TestProperty() { _myClass = new MyClass(); _proinfo = _myClass.GetType().GetProperty("MyProperty1"); _delegate = (Funcstring>)Delegate.CreateDelegate(typeof(Func string>), _proinfo.GetGetMethod(true)!); } [Benchmark] public string PropertyA() { return _myClass.MyProperty1; } [Benchmark] public string PropertyAExt() { var myClass = new MyClass(); return myClass.MyProperty1; } [Benchmark] public string PropertyB() { return _proinfo.GetValue(_myClass).ToString(); } [Benchmark] public string PropertyBExt() { var myClass = new MyClass(); var proinfo = myClass.GetType().GetProperty("MyProperty1"); return proinfo.GetValue(myClass).ToString(); } [Benchmark] public string PropertyC() { var value = _delegate(_myClass); return value; } [Benchmark] public string PropertyCExt() { var myClass = new MyClass(); var proinfo = myClass.GetType().GetProperty("MyProperty1"); var dele = (Func string>)Delegate.CreateDelegate(typeof(Func string>), proinfo.GetGetMethod(true)!); return dele(_myClass); } }
结果:PropertyC代理方式与PropertyA接近,看来在其他场景中可以参考使用。但PropertyCExt要开销的多的多,看来这是提前在实例化时做了工作,所以在代理调用时才开销变少。

想要更快更方便的了解相关知识,可以关注微信公众号