为什么不总是缓存委托实例?

唐盒

Action(SomeMethod)在这种情况下,C#编译器为什么不创建用于缓存其委托实例的代码

void MyMethod() {
   Decorator(SomeMethod);
}

void Decorator(Action a) { a(); }
void SomeMethod() { }

它仅在SomeMethod静态时执行:

static void SomeMethod() { }

编辑:

为了更清楚,让我们采用以下代码:

class A {
    public void M1() {
       var b = new B();
       b.Decorate(M2);
    }

    public void M2() {
    }
}


class B {
    public void Decorate(Action a) {
        Console.WriteLine("Calling");
        a();
    }
}

如果您想避免每次调用M1时都分配委托,您可以轻松做到,但是非常难看:

using System;

class A {
    Action _m2;

    public A() {
        _m2 = new Action(M2);
    }

    public void M1() {
       var b = new B();
       b.Decorate(_m2);
    }

     public void M2() {
     }
}


class B {
    public void Decorate(Action a) {
        Console.WriteLine("Calling");
        a();
    }
}

所以我的问题是,编译器无法生成类似代码的原因是什么?我看不到任何副作用。

我并不是说没有理由,从事编译器工作的人员比我可能会聪明得多。我只是想了解哪种情况不起作用。

马克·格雷韦尔

它不能为实例方法缓存它,因为目标实例是委托的一部分,并且它确实想对缓存使用静态字段。不会捕获任何变量等的静态方法调用可以非常便宜地进行缓存,但是当涉及到状态时,它将变得更加复杂,并this计为状态。

是的,我想可以使用实例字段进行缓存() => this.SomeMethod(),但是坦率地说,this成为目标是一种相对罕见的情况,不能解决一般问题。

但是,它也只能做这行拉姆达语法,也就是说,即使SomeMethodstatic

Decorator(SomeMethod); // not cached
Decorator(() => SomeMethod()); // cached

你可以在这里看到区别

这是因为差异是可以检测到的(不同的对象ref与相同的对象ref),并且在理论上可能会导致使用原始(非lambda)语法的现有代码中的程序行为有所不同。因此,到目前为止,缓存规定尚未追溯应用到旧语法。兼容性原因。但是,已经讨论了很多年了。IMO是像更改foreachL值捕获这样的事情之一,可以在不像我们想象的那样破坏世界的情况下进行更改。


要查看基于已编辑问题的示例中的理论差异:

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

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

C#为什么使用实例方法作为委托来分配GC0临时对象,但比缓存的委托快10%

来自分类Dev

为什么不选择实例?

来自分类Dev

为什么不总是发生堆栈溢出?

来自分类Dev

为什么不总是使用RVO / NRVO?

来自分类Dev

为什么不总是使用std :: forward?

来自分类Dev

为什么不总是四泵?

来自分类Dev

为什么不总是使用断言?

来自分类Dev

为什么不总是使用 EnableCrossPartitionQuery

来自分类Dev

为什么LINQ不缓存枚举?

来自分类Dev

为什么在C#中的委托语法也允许+ =,而总是总是指向最后一个函数

来自分类Dev

为什么不能实例化 Run 方法的委托?

来自分类Dev

为什么在缓存查询时不缓存关系?

来自分类Dev

为什么performSegueWithIdentifier总是创建一个新实例?

来自分类Dev

为什么不转换所有实例?

来自分类Dev

为什么不转换所有实例?

来自分类Dev

为什么initWithCoder不返回实例类型?

来自分类Dev

为什么POST请求不总是预检?

来自分类Dev

为什么不总是使用抽象而不是接口?

来自分类Dev

为什么导入不总是导入嵌套包?

来自分类Dev

为什么getSelection()总是不返回任何内容?

来自分类Dev

为什么不总是根据参数调用__instancecheck__?

来自分类Dev

为什么NOT IN不总是与Oracle中的MINUS检索相同的结果?

来自分类Dev

为什么不总是使用一个活动的片段

来自分类Dev

为什么不总是使用HTTPOnly和Secure cookie标志?

来自分类Dev

为什么XOR函数的这种变体不总是收敛?

来自分类Dev

.php与.html-为什么不总是使用.php?

来自分类Dev

为什么匿名类型的AssemblyQualifiedName不总是相同?

来自分类Dev

为什么不总是使用对象参数列表

来自分类Dev

为什么不总是使用抽象而不是接口?

Related 相关文章

  1. 1

    C#为什么使用实例方法作为委托来分配GC0临时对象,但比缓存的委托快10%

  2. 2

    为什么不选择实例?

  3. 3

    为什么不总是发生堆栈溢出?

  4. 4

    为什么不总是使用RVO / NRVO?

  5. 5

    为什么不总是使用std :: forward?

  6. 6

    为什么不总是四泵?

  7. 7

    为什么不总是使用断言?

  8. 8

    为什么不总是使用 EnableCrossPartitionQuery

  9. 9

    为什么LINQ不缓存枚举?

  10. 10

    为什么在C#中的委托语法也允许+ =,而总是总是指向最后一个函数

  11. 11

    为什么不能实例化 Run 方法的委托?

  12. 12

    为什么在缓存查询时不缓存关系?

  13. 13

    为什么performSegueWithIdentifier总是创建一个新实例?

  14. 14

    为什么不转换所有实例?

  15. 15

    为什么不转换所有实例?

  16. 16

    为什么initWithCoder不返回实例类型?

  17. 17

    为什么POST请求不总是预检?

  18. 18

    为什么不总是使用抽象而不是接口?

  19. 19

    为什么导入不总是导入嵌套包?

  20. 20

    为什么getSelection()总是不返回任何内容?

  21. 21

    为什么不总是根据参数调用__instancecheck__?

  22. 22

    为什么NOT IN不总是与Oracle中的MINUS检索相同的结果?

  23. 23

    为什么不总是使用一个活动的片段

  24. 24

    为什么不总是使用HTTPOnly和Secure cookie标志?

  25. 25

    为什么XOR函数的这种变体不总是收敛?

  26. 26

    .php与.html-为什么不总是使用.php?

  27. 27

    为什么匿名类型的AssemblyQualifiedName不总是相同?

  28. 28

    为什么不总是使用对象参数列表

  29. 29

    为什么不总是使用抽象而不是接口?

热门标签

归档