一说到反射,很多人都想到了性能,更有甚者直接说“慎用反射,遗患无穷”,“用反射,感觉怎么像是退步啊~”,看到这种言论,直接把反射妖魔化了,如果这种言论长此以往,势必会对很多对反射初学者造成负面影响。反射是一把双刃剑,看你怎样使用了,下面我就用代码说话。
class TestEntity { }
1. 手工创建TestEntity
[TestInfo(Category
=
"
Class.Constructor
"
, Name
=
"
Direct
"
)]
class DirectInvokeMode:IRunable
{
public void Run()
{
new TestEntity();
}
}
class DirectInvokeMode:IRunable
{
public void Run()
{
new TestEntity();
}
}
2. 反射创建TestEntity
[TestInfo(Category
=
"
Class.Constructor
"
, Name
=
"
Reflect
"
)]
class ReflectInvokeMode : IRunable
{
public void Run()
{
Activator.CreateInstance( typeof (TestEntity));
}
}
class ReflectInvokeMode : IRunable
{
public void Run()
{
Activator.CreateInstance( typeof (TestEntity));
}
}
3. 泛型反射创建TestEntity
[TestInfo(Category
=
"
Class.Constructor
"
, Name
=
"
GenericReflect
"
)]
class GenericReflectInvokeMode : IRunable
{
public void Run()
{
Activator.CreateInstance < TestEntity > ();
}
}
class GenericReflectInvokeMode : IRunable
{
public void Run()
{
Activator.CreateInstance < TestEntity > ();
}
}
4. Generic 直接创建
[TestInfo(Category
=
"
Class.Constructor
"
, Name
=
"
Generic Create
"
)]
class GenericCreateInvokeMode : IRunable
{
public void Run()
{
Create < TestEntity > ();
}
static T Create < T > () where T : new ()
{
return new T();
}
}
class GenericCreateInvokeMode : IRunable
{
public void Run()
{
Create < TestEntity > ();
}
static T Create < T > () where T : new ()
{
return new T();
}
}
[TestInfo(Category
=
"
Class.Constructor
"
, Name
=
"
Emit
"
)]
class EmitInvokeMode : IRunable
{
static readonly ConstructorHandler Ctor = typeof (TestEntity).GetConstructor(Type.EmptyTypes).GetCreator();
public void Run()
{
Ctor();
}
}
class EmitInvokeMode : IRunable
{
static readonly ConstructorHandler Ctor = typeof (TestEntity).GetConstructor(Type.EmptyTypes).GetCreator();
public void Run()
{
Ctor();
}
}
6. 不缓存Emit的创建
[TestInfo(Category
=
"
Class.Constructor
"
, Name
=
"
NoCacheEmit
"
)]
class NoCacheEmitInvokeMode : IRunable
{
public void Run()
{
typeof (TestEntity).GetConstructor(Type.EmptyTypes).GetCreator()();
}
}
class NoCacheEmitInvokeMode : IRunable
{
public void Run()
{
typeof (TestEntity).GetConstructor(Type.EmptyTypes).GetCreator()();
}
}
测试程序:(执行10万次创建Class对象)
foreach
(var item
in
Mappers)
CodeTimer.Time(item.Metadata.Category + " -> " + item.Metadata.Name, 100000 , () => item.Value.Run());
CodeTimer.Time(item.Metadata.Category + " -> " + item.Metadata.Name, 100000 , () => item.Value.Run());
输出结果:
------
Test started: Assembly: NLite.Test.dll
------
Class.Constructor -> Direct
Time Elapsed: 5ms
CPU Cycles: 0
Gen 0 : 1
Gen 1 : 0
Gen 2 : 0
Class.Constructor -> Reflect
Time Elapsed: 320ms
CPU Cycles: 2 , 968 , 750
Gen 0 : 1
Gen 1 : 0
Gen 2 : 0
Class.Constructor -> GenericReflect
Time Elapsed: 147ms
CPU Cycles: 1 , 250 , 000
Gen 0 : 1
Gen 1 : 0
Gen 2 : 0
Class.Constructor -> Generic Create
Time Elapsed: 159ms
CPU Cycles: 1 , 406 , 250
Gen 0 : 1
Gen 1 : 0
Gen 2 : 0
Class.Constructor -> Emit
Time Elapsed: 6ms
CPU Cycles: 0
Gen 0 : 2
Gen 1 : 0
Gen 2 : 0
Class.Constructor -> NoCacheEmit
Time Elapsed: 12 ,786ms
CPU Cycles: 119 , 218 , 750
Gen 0 : 162
Gen 1 : 81
Gen 2 : 0
1 passed, 0 failed, 0 skipped, took 67.77 seconds (NUnit 2.5 . 5 ).
Class.Constructor -> Direct
Time Elapsed: 5ms
CPU Cycles: 0
Gen 0 : 1
Gen 1 : 0
Gen 2 : 0
Class.Constructor -> Reflect
Time Elapsed: 320ms
CPU Cycles: 2 , 968 , 750
Gen 0 : 1
Gen 1 : 0
Gen 2 : 0
Class.Constructor -> GenericReflect
Time Elapsed: 147ms
CPU Cycles: 1 , 250 , 000
Gen 0 : 1
Gen 1 : 0
Gen 2 : 0
Class.Constructor -> Generic Create
Time Elapsed: 159ms
CPU Cycles: 1 , 406 , 250
Gen 0 : 1
Gen 1 : 0
Gen 2 : 0
Class.Constructor -> Emit
Time Elapsed: 6ms
CPU Cycles: 0
Gen 0 : 2
Gen 1 : 0
Gen 2 : 0
Class.Constructor -> NoCacheEmit
Time Elapsed: 12 ,786ms
CPU Cycles: 119 , 218 , 750
Gen 0 : 162
Gen 1 : 81
Gen 2 : 0
1 passed, 0 failed, 0 skipped, took 67.77 seconds (NUnit 2.5 . 5 ).
性能比较结果应该是一目了然了!
附上源代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using System.Reflection;
using NLite.Reflection;
namespace NLite.Test.Reflection
{
[Contract]
public interface IRunable
{
void Run();
}
//测试器元数据
public interface ITestInfo
{
//目录
string Category { get; }
//名称
string Name { get; }
}
//映射器元数据注解
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
[MetadataAttributeAttribute]
public class TestInfoAttribute : ComponentAttribute
{
public string Category { get; set; }
public string Name { get; set; }
}
[TestFixture]
public class SpecBase
{
public SpecBase()
{
}
[SetUp]
public void SetUp()
{
Given();
When();
}
public virtual void Given() { }
public virtual void When()
{
}
[Test]
public void Test()
{
}
}
public abstract class PerformanceSpecBase : SpecBase
{
[InjectMany]
protected Lazy<IRunable, ITestInfo>[] Mappers;
protected abstract void RegisterComponents();
public virtual int Times
{
get { return 100000; }
}
public override void Given()
{
RegisterComponents();
ServiceRegistry.Compose(this);
}
public override void When()
{
for (int i = 0; i < 3; i++)
{
foreach (var item in Mappers)
CodeTimer.Time(item.Metadata.Category + "->" + item.Metadata.Name, Times, () => item.Value.Run());
}
}
}
public class InvokeConstructorPerformanceSpec : PerformanceSpecBase
{
class TestEntity { }
protected override void RegisterComponents()
{
ServiceRegistry
.Register<DirectInvokeMode>()
.Register<ReflectInvokeMode>()
.Register<GenericReflectInvokeMode>()
.Register <GenericCreateInvokeMode>()
.Register<EmitInvokeMode>()
.Register < NoCacheEmitInvokeMode>()
.Register < GenericReflectInvokeMode2>()
;
}
[TestInfo(Category = "Class.Constructor", Name = "Direct")]
class DirectInvokeMode:IRunable
{
public void Run()
{
new TestEntity();
}
}
[TestInfo(Category = "Class.Constructor", Name = "Reflect")]
class ReflectInvokeMode : IRunable
{
public void Run()
{
Activator.CreateInstance(typeof(TestEntity));
}
}
[TestInfo(Category = "Class.Constructor", Name = "GenericReflect")]
class GenericReflectInvokeMode : IRunable
{
public void Run()
{
Activator.CreateInstance<TestEntity>();
}
}
[TestInfo(Category = "Class.Constructor", Name = "Reflect->Reflect")]
class GenericReflectInvokeMode2 : IRunable
{
static readonly MethodInfo CreateMethod = typeof(Activator)
.GetMethod("CreateInstance", Type.EmptyTypes)
.MakeGenericMethod(typeof(TestEntity));
public void Run()
{
CreateMethod.Invoke(null,null);
}
}
[TestInfo(Category = "Class.Constructor", Name = "Generic Create")]
class GenericCreateInvokeMode : IRunable
{
public void Run()
{
Create<TestEntity>();
}
static T Create<T>() where T : new()
{
return new T();
}
}
[TestInfo(Category = "Class.Constructor", Name = "Emit")]
class EmitInvokeMode : IRunable
{
static readonly ConstructorHandler Ctor = typeof(TestEntity).GetConstructor(Type.EmptyTypes).GetCreator();
public void Run()
{
Ctor();
}
}
[TestInfo(Category = "Class.Constructor", Name = "NoCacheEmit")]
class NoCacheEmitInvokeMode : IRunable
{
public void Run()
{
typeof(TestEntity).GetConstructor(Type.EmptyTypes).GetCreator()();
}
}
}
}
最后给大家一个思考题:Struct 创建性能大比拼的结果是怎样的?(注意Struct是值类型,Class是引用类型,值类型是分配在栈上的,引用类型是分配在堆上的)