2 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 using System.Collections.Generic;
20 using System.Reflection;
24 internal class WeakEvent<T>
26 private List<WeakHandler<T>> handlers = new List<WeakHandler<T>>();
28 public void Add(T handler)
30 handlers.Add(new WeakHandler<T>(handler));
33 public void Remove(T handler)
35 handlers.RemoveAll(item => !item.IsAlive || item.Equals(handler));
38 public void Invoke(object sender, EventArgs args)
40 var copied = handlers.ToArray();
41 foreach (var item in copied)
45 item.Invoke(sender, args);
48 handlers.Remove(item);
52 internal class WeakHandler<U>
54 private WeakReference weakReference;
55 private MethodInfo methodInfo;
57 public WeakHandler(U handler)
59 Delegate d = (Delegate)(object)handler;
60 if (d.Target != null) weakReference = new WeakReference(d.Target);
61 methodInfo = d.Method;
64 public bool Equals(U handler)
66 Delegate other = (Delegate)(object)handler;
67 return other != null && other.Target == weakReference?.Target && other.Method.Equals(methodInfo);
70 public bool IsAlive => weakReference == null || weakReference.IsAlive;
72 public void Invoke(params object[] args)
74 if (weakReference == null)
76 Delegate.CreateDelegate(typeof(U), methodInfo).DynamicInvoke(args);
80 // Because GC is done in other thread,
81 // it needs to check again that the reference is still alive before calling method.
82 // To do that, the reference should be assigned to the local variable first.
83 var localRefCopied = weakReference.Target;
85 // Do not change this to if (weakReference.Target != null)
86 if (localRefCopied != null) Delegate.CreateDelegate(typeof(U), localRefCopied, methodInfo).DynamicInvoke(args);