[英]Why not use `dynamic` instead of reflection when the property is known?
This question is similar to this one , but assuming that we know the member name at compile time. 这个问题与此类似,但是假设我们在编译时知道成员名称。
Assuming that we have a class 假设我们有一堂课
public class MyClass
{
public string TheProperty { get; set; }
}
and in another method, we want to set the TheProperty
member of an instance of that class, but we don't know the type of the instance at compile time, we only know the property name at compile time. 在另一种方法中,我们想设置该类实例的
TheProperty
成员,但是在编译时我们不知道实例的类型,而在编译时我们只知道属性名称。 So, as I see it, there are two ways to do that now: 因此,正如我所看到的,现在有两种方法可以做到这一点:
object o = new MyClass(); // For simplicity.
o.GetType().GetProperty("TheProperty").SetValue(o, "bar"); // (1)
((dynamic) o).TheProperty = "bar"; // (2)
I measured this test case using the System.Diagnostics.Stopwatch
class to find out that reflection took 475 ticks and the way using dynamic
took 0 ticks , therefore being about as fast as a direct call to new MyClass().TheProperty = "bar"
. 我使用
System.Diagnostics.Stopwatch
类测量了该测试用例,以发现反射花费了475个滴答声 ,而使用dynamic
花费了0个滴答声 ,因此与直接调用new MyClass().TheProperty = "bar"
一样快new MyClass().TheProperty = "bar"
。
Since I have almost never seen the second way, I am a little confused and my questions now are: 由于我几乎从未见过第二种方法,因此我有些困惑,现在我的问题是:
(...)reflection took 475 ticks and the way using dynamic took 0 ticks(...)
(...)反射花费475个滴答声,而使用动态的方式花费0个滴答声(...)
That is simply false. 那是完全错误的。 The problem is that you are not understanding how
dynamic
works. 问题在于您不了解
dynamic
工作原理。 I will assume you are correctly setting up the benchmark: 我将假设您正确设置了基准:
And here comes the key part you are probably not doing: 这是您可能没有做的关键部分:
And why is 3 important? 为什么3很重要? Because the runtime will cache the dynamic call and reuse it!
因为运行时将缓存动态调用并重用它! So in a naive benchmark implementation, if you are doing things right, you will incurr the cost of the initial dynamic call jitting the method and therefore you won't measure it.
因此,在幼稚的基准测试实现中,如果您做得正确,则会招致初始动态调用(使该方法无效)的开销,因此您将无法进行度量。
Run the following benchmark: 运行以下基准:
public static void Main(string[] args)
{
var repetitions = 1;
var isWarmup = true;
var foo = new Foo();
//warmup
SetPropertyWithDynamic(foo, isWarmup); //JIT method without caching the dynamic call
SetPropertyWithReflection(foo); //JIT method
var s = ((dynamic)"Hello").Substring(0, 2); //Start up the runtime compiler
for (var test = 0; test < 10; test++)
{
Console.WriteLine($"Test #{test}");
var watch = Stopwatch.StartNew();
for (var i = 0; i < repetitions; i++)
{
SetPropertyWithDynamic(foo);
}
watch.Stop();
Console.WriteLine($"Dynamic benchmark: {watch.ElapsedTicks}");
watch = Stopwatch.StartNew();
for (var i = 0; i < repetitions; i++)
{
SetPropertyWithReflection(foo);
}
watch.Stop();
Console.WriteLine($"Reflection benchmark: {watch.ElapsedTicks}");
}
Console.WriteLine(foo);
Console.ReadLine();
}
static void SetPropertyWithDynamic(object o, bool isWarmup = false)
{
if (isWarmup)
return;
((dynamic)o).TheProperty = 1;
}
static void SetPropertyWithReflection(object o)
{
o.GetType().GetProperty("TheProperty").SetValue(o, 1);
}
public class Foo
{
public int TheProperty { get; set; }
public override string ToString() => $"Foo: {TheProperty}";
}
Spot the difference between the first run and the subsequent ones? 找出第一次运行与后续运行之间的区别?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.