• 避免重复注册事件引起的内存泄漏


    偶遇需要避免重复注册事件引起的内存泄漏

    这个问题会出现在数据绑定到界面的时候,由于重新New了一个Element去显示而造成的事件注册没有取消

    此项已经更新,主要在于当前Field查找字段的时候只能查找当前Type的类型,现更改为可以向上查找父级,返回第一个查找到的字段,那么在注册的时候就不用指定写继承了INotifyPropertyChanged 或者 INotifyCollectionChanged的类型了

      1 /* 迹I柳燕
      2  * 
      3  * FileName:   JisonsINotifyOfInvocationList.cs
      4  * Version:    1.0
      5  * Date:       2014.03.18
      6  * Author:     Ji
      7  * 
      8  *========================================
      9  * @namespace  Jisons 
     10  * @class      JisonsINotifyOfInvocationList
     11  * @extends    
     12  *             
     13  *             WPF 扩展
     14  *             对于实现 INotify 接口的委托链 增 删 委托的处理
     15  * 
     16  *========================================
     17  * Hi,小喵喵...
     18  * Copyright © 迹I柳燕
     19  * 
     20  * 转载请保留...
     21  * 
     22  */
     23 
     24 using System;
     25 using System.Collections.Specialized;
     26 using System.ComponentModel;
     27 using System.Linq;
     28 using System.Reflection;
     29 
     30 namespace Jisons
     31 {
     32     public static class JisonsINotifyOfInvocationList
     33     {
     34 
     35         /// <summary> 增加委托到 _invocationList 委托列表中 ,执行重复检查</summary>
     36         /// <typeparam name="T">具有 _invocationList 链的类型</typeparam>
     37         /// <param name="data">具有线程通知的数据,此项为原委托链的数据类型</param>
     38         /// <param name="handler">增加到委托链的委托</param>
     39         /// <param name="isINotifyCollectionChanged">当前类型是否为 INotifyCollectionChanged</param>
     40         /// <returns>执行增加是否成功</returns>
     41         static bool JudgeAddEventHandler<T>(this object data, Delegate handler, bool isINotifyCollectionChanged)
     42         {
     43             bool canAdd_invocation = false;
     44 
     45             if (data == null)
     46             {
     47                 return canAdd_invocation;
     48             }
     49             try
     50             {
     51                 var collectionchangedValue = handler;
     52                 var flag = BindingFlags.Instance | BindingFlags.NonPublic;
     53 
     54                 string changed = string.Empty;
     55                 FieldInfo judgechanged = null;
     56                 if (isINotifyCollectionChanged)
     57                 {
     58                     changed = "CollectionChanged";
     59                     judgechanged = typeof(T).FindField(changed, flag);
     60                 }
     61                 else
     62                 {
     63                     changed = "PropertyChanged";
     64                     judgechanged = typeof(T).FindField(changed, flag);
     65                 }
     66 
     67                 if (judgechanged == null)
     68                 {
     69                     return canAdd_invocation;
     70                 }
     71 
     72                 var collectionvalue = judgechanged.GetValue(data);
     73                 if (collectionvalue != null)
     74                 {
     75                     var collectionlist = typeof(MulticastDelegate).FindField("_invocationList", flag).GetValue(collectionvalue) as object[];
     76                     if (collectionlist != null)
     77                     {
     78                         #region Judge Distinct
     79 
     80                         //In This Way To Remove The Same Handler 
     81                         //At Fact, I Want To Remove The Handler When I Add If ( collectionlist == null)
     82 
     83                         var collectionlistdistinct = collectionlist.Distinct().ToList();
     84                         int collectioncount = collectionlist.Count() - 1;
     85                         for (int i = collectioncount; i >= 0; i--)
     86                         {
     87                             var item = collectionlist[i];
     88                             if (item != null)
     89                             {
     90                                 if (collectionlistdistinct.Contains(item))
     91                                 {
     92                                     collectionlistdistinct.Remove(item);
     93                                 }
     94                                 else
     95                                 {
     96                                     Delegate collectionchangedValueTemp = null;
     97                                     if (isINotifyCollectionChanged)
     98                                     {
     99                                         collectionchangedValueTemp = item as NotifyCollectionChangedEventHandler;
    100                                     }
    101                                     else
    102                                     {
    103                                         collectionchangedValueTemp = item as PropertyChangedEventHandler;
    104                                     }
    105 
    106                                     if (collectionchangedValueTemp != null)
    107                                     {
    108                                         var method = typeof(T).GetEvent(changed);
    109                                         if (method != null)
    110                                         {
    111                                             method.RemoveEventHandler(data, collectionchangedValueTemp);
    112                                         }
    113                                     }
    114                                 }
    115                             }
    116                         }
    117 
    118                         #endregion
    119 
    120                         if (collectionlist != null && !collectionlist.Contains(collectionchangedValue))
    121                         {
    122                             canAdd_invocation = true;
    123                         }
    124                     }
    125 
    126                     //In The Second To Add Handle , Can Not Find The Data Of collectionlist
    127                     else
    128                     {
    129                         var method = typeof(T).GetEvent(changed);
    130                         method.RemoveEventHandler(data, collectionchangedValue);
    131                         method.AddEventHandler(data, collectionchangedValue);
    132                     }
    133                 }
    134                 else
    135                 {
    136                     canAdd_invocation = true;
    137                 }
    138 
    139                 if (canAdd_invocation)
    140                 {
    141                     var method = typeof(T).GetEvent(changed);
    142                     method.AddEventHandler(data, collectionchangedValue);
    143                 }
    144             }
    145             catch
    146             {
    147                 throw new Exception("Add Event Handler Unsuccess ...");
    148             }
    149 
    150             return canAdd_invocation;
    151         }
    152 
    153         /// <summary> 清空具有 _invocationList 的委托列表 </summary>
    154         /// <typeparam name="T">具有 _invocationList 链的类型</typeparam>
    155         /// <param name="data">具有线程通知的数据</param>
    156         /// <param name="remove_targetdata">删除指定类型中的所有此类型注册委托</param>
    157         /// <param name="isINotifyCollectionChanged">当前类型是否为 INotifyCollectionChanged</param>
    158         /// <returns>执行删除是否成功</returns>
    159         static bool JudgeRemoveEventHandler<T>(this object data, object remove_targetdata, bool isINotifyCollectionChanged)
    160         {
    161             if (data == null)
    162             {
    163                 return false;
    164             }
    165 
    166             bool canRemove_invocation = false;
    167 
    168             var flag = BindingFlags.Instance | BindingFlags.NonPublic;
    169 
    170             string changed = string.Empty;
    171             FieldInfo judgechanged = null;
    172             if (isINotifyCollectionChanged)
    173             {
    174                 changed = "CollectionChanged";
    175                 judgechanged = typeof(T).FindField(changed, flag);
    176             }
    177             else
    178             {
    179                 changed = "PropertyChanged";
    180                 judgechanged = typeof(T).FindField(changed, flag);
    181             }
    182 
    183             if (judgechanged == null)
    184             {
    185                 return canRemove_invocation;
    186             }
    187 
    188             var collectionvalue = judgechanged.GetValue(data);
    189             if (collectionvalue != null)
    190             {
    191                 var collectionlist = typeof(MulticastDelegate).FindField("_invocationList", flag).GetValue(collectionvalue) as object[];
    192                 if (collectionlist != null)
    193                 {
    194                     int collectioncount = collectionlist.Count() - 1;
    195                     for (int i = collectioncount; i >= 0; i--)
    196                     {
    197                         var item = collectionlist[i];
    198                         if (item != null)
    199                         {
    200                             var target = typeof(Delegate).FindField("_target", flag).GetValue(item);
    201                             bool canRemove = target == null || target.Equals(remove_targetdata);
    202                             if (canRemove)
    203                             {
    204                                 Delegate collectionchangedValueTemp = null;
    205                                 if (isINotifyCollectionChanged)
    206                                 {
    207                                     collectionchangedValueTemp = item as NotifyCollectionChangedEventHandler;
    208                                 }
    209                                 else
    210                                 {
    211                                     collectionchangedValueTemp = item as PropertyChangedEventHandler;
    212                                 }
    213 
    214                                 if (collectionchangedValueTemp == null)
    215                                 {
    216                                     return canRemove_invocation;
    217                                 }
    218 
    219                                 var method = typeof(T).GetEvent(changed);
    220                                 method.RemoveEventHandler(data, collectionchangedValueTemp);
    221                                 canRemove_invocation = true;
    222                             }
    223                         }
    224                     }
    225                 }
    226             }
    227 
    228             return canRemove_invocation;
    229         }
    230 
    231         /// <summary> 对 INotifyPropertyChanged 的委托链增加委托函数 </summary>
    232         /// <typeparam name="T">具有线程通知的传入类型</typeparam>
    233         /// <param name="property">实现线程通知的类型</param>
    234         /// <param name="handler">将要增加的委托</param>
    235         /// <returns>是否增加成功</returns>
    236         public static bool AddPropertyEventHandler<T>(this INotifyPropertyChanged property, PropertyChangedEventHandler handler)
    237         {
    238             return JudgeAddEventHandler<T>(property, handler, false);
    239         }
    240 
    241         /// <summary> 对 INotifyCollectionChanged 的委托链增加委托函数 </summary>
    242         /// <typeparam name="T">具有线程通知的传入类型</typeparam>
    243         /// <param name="collection">实现线程通知的类型</param>
    244         /// <param name="handler">将要增加的委托</param>
    245         /// <returns>是否增加成功</returns>
    246         public static bool AddCollectionEventHandler<T>(this INotifyCollectionChanged collection, NotifyCollectionChangedEventHandler handler)
    247         {
    248             return JudgeAddEventHandler<T>(collection, handler, true);
    249         }
    250 
    251         /// <summary> 对 INotifyPropertyChanged 的委托链删除指定Target的委托函数 </summary>
    252         /// <typeparam name="T">具有线程通知的传入类型</typeparam>
    253         /// <param name="property">将要增加的委托</param>
    254         /// <param name="remove_targetdata"></param>
    255         /// <returns>是否删除成功</returns>
    256         public static bool RemovePropertyEventHandler<T>(this INotifyPropertyChanged property, object remove_targetdata)
    257         {
    258             return JudgeRemoveEventHandler<T>(property, remove_targetdata, false);
    259         }
    260 
    261         /// <summary> 对 INotifyCollectionChanged 的委托链删除指定Target的委托函数 </summary>
    262         /// <typeparam name="T">具有线程通知的传入类型</typeparam>
    263         /// <param name="collection">实现线程通知的类型</param>
    264         /// <param name="remove_targetdata">将要增加的委托</param>
    265         /// <returns>是否删除成功</returns>
    266         public static bool RemoveCollectionEventHandler<T>(this INotifyCollectionChanged collection, object remove_targetdata)
    267         {
    268             return JudgeRemoveEventHandler<T>(collection, remove_targetdata, true);
    269         }
    270 
    271     }
    272 }
    JisonsINotifyOfInvocationList

    此项为 FindField

      1 using System;
      2 using System.Collections.Generic;
      3 using System.Linq;
      4 using System.Reflection;
      5 using System.Text;
      6 
      7 namespace Jisons
      8 {
      9     public static class JisonsFindClassInfo
     10     {
     11 
     12         /// <summary> 从当前类型一直向上查找指定名称的字段 </summary>
     13         /// <param name="type"> 查找的起始类型 </param>
     14         /// <param name="fieldName"> 字段的名称 </param>
     15         /// <param name="bindingAttr"> 搜索的标志 </param>
     16         /// <returns> 返回查询到的  FieldInfo </returns>
     17         public static FieldInfo FindField(this Type type, string fieldName, BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.NonPublic)
     18         {
     19             if (!string.IsNullOrWhiteSpace(fieldName))
     20             {
     21                 var field = type.GetField(fieldName, bindingAttr);
     22                 if (field != null)
     23                 {
     24                     return field;
     25                 }
     26                 else if (type.BaseType != null)
     27                 {
     28                     return type.BaseType.FindField(fieldName, bindingAttr);
     29                 }
     30             }
     31             return null;
     32         }
     33 
     34         /// <summary> 从当前类型一直向上查找指定名称的属性 </summary>
     35         /// <param name="type"> 查找的起始类型 </param>
     36         /// <param name="fieldName"> 属性的名称 </param>
     37         /// <param name="bindingAttr"> 搜索的标志 </param>
     38         /// <returns> 返回查询到的  PropertyInfo </returns>
     39         public static PropertyInfo FindProperty(this Type type, string propertyName, BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.NonPublic)
     40         {
     41             if (!string.IsNullOrWhiteSpace(propertyName))
     42             {
     43                 var property = type.GetProperty(propertyName, bindingAttr);
     44                 if (property != null)
     45                 {
     46                     return property;
     47                 }
     48                 else if (type.BaseType != null)
     49                 {
     50                     return type.BaseType.FindProperty(propertyName, bindingAttr);
     51                 }
     52             }
     53             return null;
     54         }
     55 
     56         /// <summary> 查询当前程序集所拥有的指定类型字段字段元数据集合 </summary>
     57         /// <typeparam name="T"> 指定查询的类型 </typeparam>
     58         /// <param name="assembly"> 查选的程序集 </param>
     59         /// <param name="bindingAttr"> 查询的指定参数 </param>
     60         /// <returns> 查询到的字段元数据集合 </returns>
     61         public static IList<FieldInfo> FindFieldInAssembly<T>(this Assembly assembly, BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.NonPublic) where T : class
     62         {
     63             IList<FieldInfo> datas = new List<FieldInfo>();
     64 
     65             var classTypes = assembly.GetTypes();
     66             foreach (var item in classTypes)
     67             {
     68                 var fields = item.GetFields(bindingAttr);
     69                 if (fields.Count() > 0)
     70                 {
     71                     var fieldType = typeof(T);
     72                     //此处在大量数据时曾试过并行获取 Parallel.ForEach
     73                     //不幸的发现会更慢
     74                     foreach (var field in fields)
     75                     {
     76                         if (field.FieldType.Equals(fieldType))
     77                         {
     78                             datas.Add(field);
     79                         }
     80                     }
     81                 }
     82             }
     83 
     84             return datas;
     85         }
     86 
     87         /// <summary> 查询当前程序集所拥有的指定类型静态字段集合 </summary>
     88         /// <typeparam name="T"> 指定查询的类型 </typeparam>
     89         /// <param name="assembly"> 查选的程序集 </param>
     90         /// <param name="bindingAttr"> 查询的指定参数 </param>
     91         /// <returns>查询到指定静态类型的值集合</returns>
     92         public static IList<T> FindStaticFieldValueInAssembly<T>(this Assembly assembly, BindingFlags bindingAttr = BindingFlags.Static | BindingFlags.Public) where T : class
     93         {
     94             IList<T> datas = new List<T>();
     95 
     96             var fieldList = assembly.FindFieldInAssembly<T>(bindingAttr);
     97             if (fieldList.Count > 0)
     98             {
     99                 //此处在大量数据时曾试过并行获取 Parallel.ForEach
    100                 //不幸的发现会更慢
    101                 fieldList.ForEach(i =>
    102                 {
    103                     var data = i.GetValue(null) as T;
    104                     if (data != null)
    105                     {
    106                         datas.Add(data);
    107                     }
    108                 });
    109             }
    110 
    111             return datas;
    112         }
    113 
    114         /// <summary> 查询当前程序集所拥有的指定类型接口的接口元数据集合 </summary>
    115         /// <typeparam name="T"> 指定查询类型的接口 </typeparam>
    116         /// <param name="assembly"> 查选的程序集 </param>
    117         /// <param name="bindingAttr"> 查询的指定参数 </param>
    118         /// <returns> 查询到的字段元数据集合 </returns>
    119         public static IDictionary<Type, Type> FindInterfacesInAssembly<T>(this Assembly assembly, BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.NonPublic) where T : class
    120         {
    121             IDictionary<Type, Type> datas = new Dictionary<Type, Type>();
    122 
    123             var classTypes = assembly.GetTypes();
    124             var returnType = typeof(T).Name;
    125             foreach (var item in classTypes)
    126             {
    127                 var interfaces = item.GetInterfaces();
    128                 if (interfaces.Count() > 0)
    129                 {
    130                     var interfaceOfT = interfaces.FirstOrDefault(i => i.Name.Equals(returnType));
    131                     if (interfaceOfT != null)
    132                     {
    133                         datas.Add(item, interfaceOfT);
    134                     }
    135                 }
    136             }
    137             return datas;
    138         }
    139 
    140         /*  test
    141        
    142          * /// <summary> 获取继承接口而实现添加的快捷键子项集合 </summary>
    143         /// <param name="currentAssembly"></param>
    144         /// <returns></returns>
    145         public static List<RoutedCommandsHotKeys> GetInterfaceHotKeys(this Assembly currentAssembly)
    146         {
    147             var referencedAssemblies = currentAssembly.GetReferencedAssemblies().ToList();
    148             referencedAssemblies.Add(currentAssembly.GetName());
    149 
    150             List<RoutedCommandsHotKeys> datas = new List<RoutedCommandsHotKeys>();
    151             Parallel.ForEach(referencedAssemblies, referencedAssembly =>
    152             {
    153                 var assembly = Assembly.Load(referencedAssembly);
    154                 var data = assembly.FindInterfacesInAssembly<IHotKeys>();
    155                 if (data != null)
    156                 {
    157                     foreach (var interfaceDictionary in data)
    158                     {
    159                         var methods = interfaceDictionary.Value.GetMethods();
    160                         var returnType = typeof(List<RoutedCommandsHotKeys>);
    161                         var methodOfIHotKeys = methods.FirstOrDefault(i => i.ReturnType.Equals(returnType));
    162                         if (methodOfIHotKeys != null)
    163                         {
    164                             var property = interfaceDictionary.Key.FindProperty("CurrenttRoutedCommandsTarget", BindingFlags.Instance | BindingFlags.Public);
    165                             if (property != null)
    166                             {
    167                                 try
    168                                 {
    169                                     //此时线程并不在UI线程,切要优化效率因此并不做移交到UI线程处理
    170                                     //因此,实现接口的函数不能是需要在UI线程创建的class,例如UIElement
    171                                     object obj = interfaceDictionary.Key.GetConstructor(Type.EmptyTypes).Invoke(null);
    172                                     var value = methodOfIHotKeys.Invoke(obj, null) as List<RoutedCommandsHotKeys>;
    173                                     if (value != null)
    174                                     {
    175                                         datas.AddRange(value);
    176                                     }
    177                                 }
    178                                 catch (Exception ex)
    179                                 {
    180                                     Console.WriteLine(ex.Message);
    181                                 }
    182                             }
    183                         }
    184                     }
    185                 }
    186             });
    187 
    188             return datas;
    189         }
    190 
    191          * */
    192 
    193     }
    194 }
    FindField
  • 相关阅读:
    Android 聊天表情输入、表情翻页带效果、下拉刷新聊天记录
    android启动界面
    ubuntu 关于sublime text3的一些应用
    [LeetCode]Valid Sudoku解题记录
    在 Mac OS X 10.10 安装 pyenv 的一个小坑
    java调用百度地图API依据地理位置中文获取经纬度
    debug openStack
    error recoder,error debug for openStack kilo
    SDN,NFV
    openStack kilo 手动Manual部署随笔记录
  • 原文地址:https://www.cnblogs.com/jiailiuyan/p/3498942.html
Copyright © 2020-2023  润新知