代表,行动和记忆分配

 完美美容店 发布于 2023-02-13 10:21

我目前正在处理一块需要最少内存分配的代码.

我注意到如果我使用参数的方法编译器更改代码并创建一个新的Action,但是如果我使用匿名方法编译器创建一个委托块,我知道新的Action分配内存,但我对代表不太确定.代表们在使用时会分配内存吗?

我的守则

 bool workfinished = false;
    void DoWork()
    {

    MyMethod(  CallBack1Work ,()=>{ workfinished = false;});

    }

    void MyMethod(Action callback1 ,Action callback2)
    {

    }

    void CallBack1Work()
    {

    }

编译器版本

bool workfinished = false;


        void DoWork{

        MyMethod( new Action( CallBack1Work ),delegate{ 
                                                      workfinished = false; 
                                                       });

        }
        void MyMethod(Action callback1 ,Action callback2)
        {

        }

        void CallBack1Work()
        {

        }

        void DoWork_b01()
        {
             workfinished = false;
        }

提前致谢!

2 个回答
  • 无论是显式使用new SomeDelegate还是省略它,无论是使用lambda,delegate关键字还是传递方法组,还是未显示任何可能的解决方案,都无关紧要.在每种情况下,都会创建一个委托对象.编译器通常可以推断它应该在那里,所以它不会强迫你输入它; 但无论如何,该代表的创建仍在发生.(嗯,从技术上讲,你可以传入null而不是分配一个对象,但是你不能做任何工作,所以我认为忽略这种情况是安全的.)

    每个选项之间内存分配的唯一真正区别在于,在给定的匿名方法块中,您将关闭变量(workfinished).为了创建该闭包,运行时将生成它自己的类型来存储闭包的状态,创建该类型的实例,并将其用于委托,因此所有使用匿名方法的解决方案都在创建一个新对象.(当然,它很小,所以在大多数情况下它不会特别昂贵.)

    2023-02-13 10:23 回答
  • 如果你使用一个不捕获任何东西的lambda表达式,编译器将生成一个静态字段来缓存它.所以使用它,你可以改变Action为a Action<YourClass>并调用它this.所以:

    class YourClass
    {
        private bool workFinished;
    
        public void DoWork()
        {
            MyMethod(instance => instance.Callback1Work(),
                     instance => instance.workFinished = false);
        }
    
        private void MyMethod(Action<YourClass> callback1,
                              Action<YourClass> callback2)
        {
            // Do whatever you want here...
            callback1(this);
            // And here...
            callback2(this);
        }
    
        private void Callback1Work()
        {
           // ...
        }
    }
    

    只会在第一次DoWork任何实例上调用时创建委托实例.然后将为所有实例的所有未来调用缓存代理.

    不可否认,这只是一个实施细节.你总是可以让它更清晰:

    class YourClass
    {
        private static readonly Action<YourClass> Callback1 = x => x.Callback1Work();
        private static readonly Action<YourClass> Callback2 = x => x.workFinished = false;
    
        private bool workFinished;
    
        public void DoWork()
        {
            MyMethod(Callback1, Callback2);
        }
    
        ... code as before ...
    }
    

    在你进入任何这些长度之前,实际上值得对代码进行分析和基准测试.

    另一种选择是坚持Action,但为代表创建实例变量 - 所以只要你DoWork在同一个实例上多次调用,你就可以了:

    class YourClass
    {
        private readonly Action foo;
        private readonly Action bar;
    
        private bool workFinished;
    
        public YourClass()
        {
            foo = Callback1Work;
            bar = () => workFinished = false;
        }
    
        public void DoWork()
        {
            MyMethod(foo, bar);
        }
    
        public void MyMethod(Action callback1, Action callback2)
        {
            ...
        }
    
        private void Callback1Work()
        {
            ...
        }
    }
    

    2023-02-13 10:23 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有