IDisposable的另类用法

IDisposable是.Net中一个很重要的接口,一般用来释放非托管资源,我们知道在使用了IDisposable的对象之后一定要调用IDisposable.Dispose()方法,或者使用.Net提供的关键字using来达到这一目的,如:

        public void ReadFile()
        {
            using (var reader=new StreamReader("c:\\test.txt"))
            {
               var text= reader.ReadToEnd();
                Console.WriteLine(text);
            }
        } 

使用using关键字后,编译器将在他的末尾自动插入一个Dispose方法的调用。我们可以利用这一点尝试完成下面的需求:

我们希望将警告的文本以红色显示在控制台上,然后再恢复初始颜色显示其他文本内容。按照传统做法,我们先存储初始颜色,设定新颜色,向控制台输出警告信息,恢复初始颜色,输出其他文本。

        public void Show()
        {
            var originalColor = Console.ForegroundColor;

            Console.ForegroundColor = ConsoleColor.Red;

            Console.WriteLine("dangerous message");

            Console.ForegroundColor = originalColor;
            Console.WriteLine("other message");
        }

如果利用我们前面分析的IDisposable模式,我们先实现一个能够接收Action类型的通用Disposable:

    public class DisposableAction:IDisposable
    {
        private readonly Action _action;

        public DisposableAction(Action action)
        {
            _action = action;
        }

        public void Dispose()
        {
            _action();
        }
    }

进一步实现之前的需求

       public void Show()
        {
            var originalColor = Console.ForegroundColor;

            using (new DisposableAction(()=>Console.ForegroundColor=originalColor))
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("dangerous message");
            }

            Console.WriteLine("other message");
        }

这似乎也没比上面高明多少,是因为这个例子不能够展现这个模式的威力。在《三种观察者模式的C#实现》一文中,我介绍的第三种方案是利用Action来实现,而该文并没有给出如何取消订阅的方法。利用本文的内容将会实现一个优雅的取消订阅方案:

       public IDisposable OnAlarm(Action<AlarmData> alarmAction)
        {
            _alarmActions.Add(alarmAction);

            return new DisposedAction(()=>_alarmActions.Remove(alarmAction));
        }

如果想只订阅一次,就使用using:

 using (_clock.OnAlarm(data => {/*alarm*/ }))
            {
                
            }

反之,如果不想取消订阅就不要使用using,不要调用Dispose()方法。

相关文章

这篇文章主要讲解了“WPF如何实现带筛选功能的DataGrid”,文...
本篇内容介绍了“基于WPF如何实现3D画廊动画效果”的有关知识...
Some samples are below for ASP.Net web form controls:(fr...
问题描述: 对于未定义为 System.String 的列,唯一有效的值...
最近用到了CalendarExtender,结果不知道为什么发生了错位,...
ASP.NET 2.0 page lifecyle ASP.NET 2.0 event sequence cha...