偶遇需要避免重复注册事件引起的内存泄漏
这个问题会出现在数据绑定到界面的时候,由于重新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 }
此项为 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 }