[NUI] Fix comments according to document review
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / internal / Common / WeakEvent.cs
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 using System;
19 using System.Collections.Generic;
20 using System.Reflection;
21
22 namespace Tizen.NUI
23 {
24     internal class WeakEvent<T>
25     {
26         private List<WeakHandler<T>> handlers = new List<WeakHandler<T>>();
27
28         public void Add(T handler)
29         {
30             handlers.Add(new WeakHandler<T>(handler));
31         }
32
33         public void Remove(T handler)
34         {
35             handlers.RemoveAll(item => !item.IsAlive || item.Equals(handler));
36         }
37
38         public void Invoke(object sender, EventArgs args)
39         {
40             var copied = handlers.ToArray();
41             foreach (var item in copied)
42             {
43                 if (item.IsAlive)
44                 {
45                     item.Invoke(sender, args);
46                     continue;
47                 }
48                 handlers.Remove(item);
49             }
50         }
51
52         internal class WeakHandler<U>
53         {
54             private WeakReference weakReference;
55             private MethodInfo methodInfo;
56
57             public WeakHandler(U handler)
58             {
59                 Delegate d = (Delegate)(object)handler;
60                 if (d.Target != null) weakReference = new WeakReference(d.Target);
61                 methodInfo = d.Method;
62             }
63
64             public bool Equals(U handler)
65             {
66                 Delegate other = (Delegate)(object)handler;
67                 return other != null && other.Target == weakReference?.Target && other.Method.Equals(methodInfo);
68             }
69
70             public bool IsAlive => weakReference == null || weakReference.IsAlive;
71
72             public void Invoke(params object[] args)
73             {
74                 if (weakReference == null)
75                 {
76                     Delegate.CreateDelegate(typeof(U), methodInfo).DynamicInvoke(args);
77                 }
78                 else
79                 {
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;
84
85                     // Do not change this to if (weakReference.Target != null)
86                     if (localRefCopied != null) Delegate.CreateDelegate(typeof(U), localRefCopied, methodInfo).DynamicInvoke(args);
87                 }
88             }
89         }
90     }
91 }