我对所搜索的术语的知识有限,因此我进行了尽可能多的搜索,但是我找不到并回答我所追求的问题。
我很惊讶地发现,用数据填充对象Reflection比使用更快object Initialization。
为此,我制作了一个测试控制台应用程序。首先是测试班
class TestClass
{
public string PropertyOne { get; set; }
public string PropertyTwo { get; set; }
public string PropertyThree { get; set; }
public string PropertyFour { get; set; }
public string PropertyFive { get; set; }
public string PropertySix { get; set; }
public string PropertySeven { get; set; }
public string PropertyEight { get; set; }
public string PropertyNine { get; set; }
public string PropertyTen { get; set; }
}
}
Run Code Online (Sandbox Code Playgroud)
然后是获取数据的方法,首先是反射
public static void ReflectionTest()
{
for (int i = 0; i < 10000000; i++)
{
TestClass testClass = new TestClass();
Type type = testClass.GetType();
PropertyInfo[] properties = type.GetProperties();
foreach (var propertyInfo in properties)
{
switch (propertyInfo.Name)
{
case nameof(testClass.PropertyOne):
propertyInfo.SetValue(testClass, "PropertyOne" + i);
break;
case nameof(testClass.PropertyTwo):
propertyInfo.SetValue(testClass, "PropertyTwo" + i);
break;
case nameof(testClass.PropertyThree):
propertyInfo.SetValue(testClass, "PropertyThree" + i);
break;
case nameof(testClass.PropertyFour):
propertyInfo.SetValue(testClass, "PropertyFour" + i);
break;
case nameof(testClass.PropertyFive):
propertyInfo.SetValue(testClass, "PropertyFive)" + i);
break;
case nameof(testClass.PropertySix):
propertyInfo.SetValue(testClass, "PropertySix" + i);
break;
case nameof(testClass.PropertySeven):
propertyInfo.SetValue(testClass, "PropertySeven" + i);
break;
case nameof(testClass.PropertyEight):
propertyInfo.SetValue(testClass, "PropertyEight" + i);
break;
case nameof(testClass.PropertyNine):
propertyInfo.SetValue(testClass, "PropertyNine" + i);
break;
case nameof(testClass.PropertyTen):
propertyInfo.SetValue(testClass, "PropertyTen" + i);
break;
}
}
TestClasses.Add(testClass);
}
}
Run Code Online (Sandbox Code Playgroud)
接下来是对象的初始化
public static void InitializationTest()
{
for (int i = 0; i < 10000000; i++)
{
TestClass testClass = new TestClass
{
PropertyOne = "PropertyOne" + i,
PropertyTwo = "PropertyTwo" + i,
PropertyThree = "PropertyThree" + i,
PropertyFour = "PropertyFour" + i,
PropertyFive = "PropertyFive)" + i,
PropertySix = "PropertySix" + i,
PropertySeven = "PropertySeven" + i,
PropertyEight = "PropertyEight" + i,
PropertyNine = "PropertyNine" + i,
PropertyTen = "PropertyTen" + i
};
TestClasses.Add(testClass);
}
}
Run Code Online (Sandbox Code Playgroud)
和测试代码
static List<TestClass> TestClasses { get; set; } = new List<TestClass>();
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
sw.Start();
ReflectionTest();
Console.WriteLine($"Reflection Test time: {sw.Elapsed}");
sw.Reset();
sw.Start();
InitializationTest();
Console.WriteLine($"Initialization Test time: {sw.Elapsed}");
sw.Stop();
}
Run Code Online (Sandbox Code Playgroud)
使用此代码,使用对象初始化的反射速度提高了20%。这是什么原因呢?
编辑:添加TestClasses.Clear();到代码中,表明“对象初始化”几乎快了一倍。感谢您的答复和评论。
这种测量没有意义-否则每个人都将使用反射而不是对象实例。
结果令人困惑的主要原因是所有项目都被添加到同一列表中。以不同的顺序调用测试并获得InitializationTest更好的性能。
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
sw.Start();
InitializationTest();
Console.WriteLine($"Initialization Test time: {sw.Elapsed}");
sw.Stop();
sw.Reset();
sw.Start();
ReflectionTest();
Console.WriteLine($"Reflection Test time: {sw.Elapsed}");
sw.Stop();
sw.Reset();
Console.ReadLine();
}
Run Code Online (Sandbox Code Playgroud)
正如Matthew Watson在评论中所言:“更好的是,不要将所有列表用作计时的一部分。我们应该计时的时间是创建对象需要多长时间-而不是填充一个非常长的时间。大名单。”
反思测试包括不必要的费用:重复GetProperties发票,交换机中的测试条件
public static void ReflectionTest()
{
PropertyInfo[] properties = typeof(TestClass).GetProperties();
for (int i = 0; i < 10000000; i++)
{
TestClass testClass = new TestClass();
foreach (var propertyInfo in properties)
{
propertyInfo.SetValue(testClass, propertyInfo.Name + i);
}
TestClasses.Add(testClass);
}
}
Run Code Online (Sandbox Code Playgroud)
基准测试很难。始终使用BenchmarkDotNet。
我使用BenchmarkDotNet重写了您的测试,并得到了以下结果:
BenchmarkDotNet=v0.12.0, OS=Windows 10.0.18362
Intel Core i5-3317U CPU 1.70GHz (Ivy Bridge), 1 CPU, 4 logical and 2 physical cores
.NET Core SDK=3.0.100-preview6-012264
[Host] : .NET Core 3.0.0 (CoreCLR 4.700.19.30373, CoreFX 4.700.19.30308), X64 RyuJIT
DefaultJob : .NET Core 3.0.0 (CoreCLR 4.700.19.30373, CoreFX 4.700.19.30308), X64 RyuJIT
Run Code Online (Sandbox Code Playgroud)
| Method | Mean | Error | StdDev |
|----------- |-------------|-----------|-----------|
| Instance | 41.61 ns | 0.309 ns | 0.274 ns |
| Reflection | 3,321.40 ns | 28.379 ns | 25.157 ns |
Run Code Online (Sandbox Code Playgroud)
这清楚地表明您的反射代码比使用对象初始化程序慢80倍左右。
@ASh的答案是关于您的基准测试为什么有缺陷的原因,因此,我在这里不再重复,请参阅他们的答案。
基准代码:
public class Benchmark
{
[Benchmark]
public TestClass Instance()
{
TestClass testClass = new TestClass
{
PropertyOne = "PropertyOne",
PropertyTwo = "PropertyTwo",
PropertyThree = "PropertyThree",
PropertyFour = "PropertyFour",
PropertyFive = "PropertyFive)",
PropertySix = "PropertySix",
PropertySeven = "PropertySeven",
PropertyEight = "PropertyEight",
PropertyNine = "PropertyNine",
PropertyTen = "PropertyTen"
};
return testClass;
}
[Benchmark]
public TestClass Reflection()
{
TestClass testClass = new TestClass();
Type type = testClass.GetType();
PropertyInfo[] properties = type.GetProperties();
foreach (var propertyInfo in properties)
{
switch (propertyInfo.Name)
{
case nameof(testClass.PropertyOne) :
propertyInfo.SetValue(testClass, "PropertyOne");
break;
case nameof(testClass.PropertyTwo) :
propertyInfo.SetValue(testClass, "PropertyTwo");
break;
case nameof(testClass.PropertyThree) :
propertyInfo.SetValue(testClass, "PropertyThree");
break;
case nameof(testClass.PropertyFour) :
propertyInfo.SetValue(testClass, "PropertyFour");
break;
case nameof(testClass.PropertyFive) :
propertyInfo.SetValue(testClass, "PropertyFive");
break;
case nameof(testClass.PropertySix) :
propertyInfo.SetValue(testClass, "PropertySix");
break;
case nameof(testClass.PropertySeven) :
propertyInfo.SetValue(testClass, "PropertySeven");
break;
case nameof(testClass.PropertyEight) :
propertyInfo.SetValue(testClass, "PropertyEight");
break;
case nameof(testClass.PropertyNine) :
propertyInfo.SetValue(testClass, "PropertyNine");
break;
case nameof(testClass.PropertyTen) :
propertyInfo.SetValue(testClass, "PropertyTen");
break;
}
}
return testClass;
}
}
class Program
{
public static void Main()
{
var summary = BenchmarkRunner.Run(typeof(Program).Assembly);
}
}
Run Code Online (Sandbox Code Playgroud)