Он не может кэшировать его для экземпляров методов, поскольку целевой экземпляр является частью делегата , и он действительно хочет использовать данные c поле для кеша. Вызов метода stati c, который не захватывает никакие переменные и т. Д. c, может быть кэширован очень дешево, но становится намного сложнее, когда задействовано состояние, и this
считается состоянием.
Да, я полагаю, можно использовать поле экземпляра для кэширования () => this.SomeMethod()
, но, честно говоря, this
, являющийся целью, является относительно редким случаем и не решает общую проблему.
Однако, это также только делает это для лямбда синтаксиса, т.е. даже если SomeMethod
равен static
Decorator(SomeMethod); // not cached
Decorator(() => SomeMethod()); // cached
Вы можете увидеть разницу здесь
Это это потому, что разница обнаружима (разные ссылки на объекты и те же ссылки на объекты) и может в теории привести к другому поведению программы в существующем коде, который использовал оригинальный (не лямбда) синтаксис; таким образом, положение с кэшем до настоящего времени не применялось ретроспективно к старому синтаксису. Причины совместимости. Это обсуждалось годами, хотя; IMO, это одна из тех вещей, как изменение foreach
захватов L-значения, которое, вероятно, можно изменить, не разбивая мир так сильно, как мы себе представляем.
Чтобы увидеть теоретическую разницу в пример, основанный на отредактированном вопросе:
using System;
class A
{
static void Main()
{
var obj = new A();
Console.WriteLine("With cache...");
for (int i = 0; i < 5; i++) obj.WithCache();
Console.WriteLine("And without cache...");
for (int i = 0; i < 5; i++) obj.WithoutCache();
}
Action _m2;
B b = new B();
public void WithCache() => b.Decorate(_m2 ??= M2);
public void WithoutCache() => b.Decorate(M2);
public void M2() => Console.WriteLine("I'm M2");
}
class B
{
private object _last;
public void Decorate(Action a)
{
if (_last != (object)a)
{
a();
_last = a;
}
else
{
Console.WriteLine("No do-overs!");
}
}
}
В настоящее время выводится:
With cache...
I'm M2
No do-overs!
No do-overs!
No do-overs!
No do-overs!
And without cache...
I'm M2
I'm M2
I'm M2
I'm M2
I'm M2