属性——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<TestProperty>();
第一组:构造实例化对象和方法内实例化对象,调用属性差多少
[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 Func<MyClass, string> _delegate;
public TestProperty()
{
_myClass = new MyClass();
_proinfo = _myClass.GetType().GetProperty("MyProperty1");
_delegate = (Func<MyClass, string>)Delegate.CreateDelegate(typeof(Func<MyClass, 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<MyClass, string>)Delegate.CreateDelegate(typeof(Func<MyClass, string>), proinfo.GetGetMethod(true)!);
return dele(_myClass);
}
}
结果:PropertyC代理方式与PropertyA接近,看来在其他场景中可以参考使用。但PropertyCExt要开销的多的多,看来这是提前在实例化时做了工作,所以在代理调用时才开销变少。
想要更快更方便的了解相关知识,可以关注微信公众号