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

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

这个问题会出现在数据绑定到界面的时候,由于重新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

 

你可能感兴趣的:(内存泄漏)