.Net中的弱引用字典WeakDictionary和ConditionalWeakTable介绍

 更新时间:2022年06月26日 08:43:34   作者:天方  
这篇文章介绍了.Net中的弱引用字典WeakDictionary和ConditionalWeakTable,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

有的时候,我们需要给某些数据添加一些附加信息,一种常用的做法是使用一个Dictionary在填充这些附加信息如:

    var data = new Data();
    var tag = new Tag();

    var dictionary = new Dictionary<Data, Tag>();
    dictionary[data] = tag;

这么做本身没有什么问题,但是却又一个不小的隐患,那就是在dictionary中保存着了data和tag的引用。当data不再使用的时候,需要将其从dictionary中移除,否则data和tag得不到释放。我们可以用如下代码说明这个问题:(注意,由于Debug模式有时会影响GC,本文代码需行在Release模式下)

    class Tag
    {
        public Tag()
        {
            Console.WriteLine("Create Tag");
        }

        ~Tag()
        {
            Console.WriteLine("Release Tag");
        }
    }

    class Data
    {
        public Data()
        {
            Console.WriteLine("Create Data");
        }

        ~Data()
        {
            Console.WriteLine("Release Data");
        }
    }

    static void Main(string[] args)
    {
        var data = new Data();
        var tag = new Tag();

        var dictionary = new Dictionary<Data, Tag>();
        dictionary[data] = tag;

        data = null;
        GC.Collect();

        Console.WriteLine("After GC");
        Console.ReadLine();
        Console.WriteLine(dictionary);
    }

从运行结果中可以看出,只有创建的输出,而没有释放的输出。这个就属于资源泄漏了。虽然可以通过手动在dictionary中删除data来实现资源的释放,但是这样就要求我们手动管理对象的生命周期了,而这往往不是一个比较容易做到的事情。

究其原因,是由于dictionary中保持着强引用、导致GC不会对其进行回收。找到了这个原因后,那就有相应的对策了,那就是改用弱引用来建立关联,这样数据就会被GC释放了。这种观念关系我们通常称为弱字典——WeakDictionary。弱字典也是保存着Key和Value的键值对,它满足如下需求:

  • 字典中保存着Key的弱引用,即使不释放Key值,也可以被GC回收。

  • 字典中保存的Value的强引用,Key没有被GC回收前,Value不会被GC回收。

  • 当Key被GC回收时,关联关系从字典中移除,Value也能被GC回收。

知道了需求后,接下来就可以对Dictionary进行简单的封装,将其改造成弱字典了。

    static void Main(string[] args)
    {
        var data = new Data();
        var tag = new Tag();

        var dictionary = new Dictionary<WeakReference<Data>, Tag>();
        var key = new WeakReference<Data>(data);
        dictionary[key] = tag;

        data = null;
        GC.Collect();

        Console.WriteLine("After GC");
        Console.ReadLine();
        Console.WriteLine(dictionary);
    }

运行这段代码后,我们就会发现,Data数据能释放了,但是并不完善,具体体现在如下方面:

  • Tag保存的仍然是强引用,得不到释放

  • Key数据并不是Data类型了,存在一个检索的问题,否则无法CRUD。

对于第一个问题,可以通过一个Timer来定时清理已经释放了的Key来解决;对于第二个问题,则需要在内部通过key来建立Hash表来解决。具体的实现还有点麻烦,也会引入一些新的问题,这里就不继续列举了。

之所以不继续改造下去了,是因为这里我是在造重复轮子,.Net的BCL中本身就已经提供了一个弱字典——ConditionalWeakTable,通过ConditionalWeakTable改造上述代码如下:

    static void Main(string[] args)
    {
        var data = new Data();
        var tag = new Tag();

        var dictionary = new ConditionalWeakTable<Data, Tag>();
        dictionary.Add(data, tag);

        data = null;
        GC.Collect();

        Console.WriteLine("After GC");
        Console.ReadLine();
        Console.WriteLine(dictionary);
    }

从运行结果来看,GC结束后,Key和Value都被GC回收掉了(再次强调,需要运行在Release版本下)。

这个类放置在System.Runtime.CompilerServices下,也很少见到有书里面介绍到它。这里我就简单的介绍一下其接口吧:

    dictionary.Add(data, tag);    //添加    
    dictionary.TryGetValue(data, out tag);    //查询
    dictionary.Remove(data);    //删除

这三个是它比较常见的接口,另外还有两个不大用的接口,这里就不多介绍了。

最后,简单的试了它的性能,基本上和Dictionary差不多,查询效率还是非常高的,内部应该也是一个Hash表。

到此这篇关于.Net弱引用字典WeakDictionary和ConditionalWeakTable的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • .NET使用RSA加密解密的方法

    .NET使用RSA加密解密的方法

    这篇文章主要为大家详细介绍了.NET使用RSA加密解密的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-03-03
  • Razor模板引擎简单介绍

    Razor模板引擎简单介绍

    这篇文章主要为大家详细介绍了Razor模板引擎的简单资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-08-08
  • asp.net操作xml增删改示例分享

    asp.net操作xml增删改示例分享

    这篇文章主要介绍了asp.net操作xml增删改示例,需要的朋友可以参考下
    2014-02-02
  • 关于Metalama使用Fabric操作项目或命名空间的问题

    关于Metalama使用Fabric操作项目或命名空间的问题

    Metalama是一个基于微软编译器Roslyn的元编程的库,可以解决我在开发中遇到的重复代码的问题,这篇文章主要介绍了Metalama使用Fabric操作项目或命名空间,需要的朋友可以参考下
    2022-04-04
  • .NET Core利用swagger进行API接口文档管理的方法详解

    .NET Core利用swagger进行API接口文档管理的方法详解

    这篇文章主要给大家介绍了关于.NET Core利用swagger进行API接口文档管理的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2018-03-03
  • Visual Studio 2017 离线安装教程

    Visual Studio 2017 离线安装教程

    这篇文章主要为大家详细介绍了Visual Studio 2017 离线安装教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-03-03
  • asp.net简单页面控件赋值实现方法

    asp.net简单页面控件赋值实现方法

    这篇文章主要介绍了asp.net简单页面控件赋值实现方法,涉及数据库的查询及页面控件元素赋值操作相关技巧,需要的朋友可以参考下
    2016-07-07
  • asp.net repeater实现批量删除

    asp.net repeater实现批量删除

    asp.net repeater实现批量删除实现效果代码
    2009-03-03
  • 使用EF的Code First模式操作数据库

    使用EF的Code First模式操作数据库

    这篇文章介绍了使用EF的Code First模式操作数据库,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-03-03
  • Asp.net中时间格式化的6种方法详细总结

    Asp.net中时间格式化的6种方法详细总结

    数据控件绑定时格式化日期方法/用DataBinder.Eval进行数据绑定时/直接用ToString方法转换日期显示格式/用String类转换日期显示格式等等,感兴趣的你了解下哦,或许对你学习时间格式化有所帮助
    2013-02-02

最新评论