Mirror of Svelto.ECS because we're a fan of it
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

153 lines
4.7KB

  1. using System;
  2. using System.Reflection;
  3. using System.Runtime.CompilerServices;
  4. using System.Runtime.InteropServices;
  5. //careful, you must handle the destruction of the GCHandles!
  6. namespace Svelto.WeakEvents
  7. {
  8. public struct WeakActionStruct<T1, T2> : IEquatable<WeakActionStruct<T1, T2>>, IDisposable
  9. {
  10. public WeakActionStruct(Action<T1, T2> listener)
  11. {
  12. WeakActionStructUtility.Init(listener.Target, listener.Method, out _objectRef, out _method);
  13. }
  14. public bool Invoke(object[] args)
  15. {
  16. return WeakActionStructUtility.Invoke(ref _objectRef, _method, args);
  17. }
  18. public bool Equals(WeakActionStruct<T1, T2> other)
  19. {
  20. return WeakActionStructUtility.IsMatch(_objectRef.Target, _method,
  21. other._objectRef.Target, other._method);
  22. }
  23. public void Dispose()
  24. {
  25. _objectRef.Free();
  26. }
  27. public bool IsMatch(object otherObject, MethodInfo otherMethod)
  28. {
  29. return WeakActionStructUtility.IsMatch(_objectRef.Target, _method,
  30. otherObject, otherMethod);
  31. }
  32. GCHandle _objectRef;
  33. readonly MethodInfo _method;
  34. }
  35. public struct WeakActionStruct<T> : IEquatable<WeakActionStruct<T>>, IDisposable
  36. {
  37. public WeakActionStruct(Action<T> listener)
  38. {
  39. WeakActionStructUtility.Init(listener.Target, listener.Method,
  40. out _objectRef, out _method);
  41. }
  42. public bool Invoke(object[] args)
  43. {
  44. return WeakActionStructUtility.Invoke(ref _objectRef, _method, args);
  45. }
  46. public bool Equals(WeakActionStruct<T> other)
  47. {
  48. return WeakActionStructUtility.IsMatch(_objectRef.Target, _method,
  49. other._objectRef.Target, other._method);
  50. }
  51. public void Dispose()
  52. {
  53. _objectRef.Free();
  54. }
  55. public bool IsMatch(object otherObject, MethodInfo otherMethod)
  56. {
  57. return WeakActionStructUtility.IsMatch(_objectRef.Target, _method,
  58. otherObject, otherMethod);
  59. }
  60. GCHandle _objectRef;
  61. readonly MethodInfo _method;
  62. }
  63. public struct WeakActionStruct : IEquatable<WeakActionStruct>, IDisposable
  64. {
  65. public WeakActionStruct(Action listener)
  66. {
  67. WeakActionStructUtility.Init(listener.Target, listener.Method, out _objectRef, out _method);
  68. }
  69. public bool Invoke()
  70. {
  71. return WeakActionStructUtility.Invoke(ref _objectRef, _method, null);
  72. }
  73. public bool Equals(WeakActionStruct other)
  74. {
  75. return WeakActionStructUtility.IsMatch(_objectRef.Target, _method,
  76. other._objectRef.Target, other._method);
  77. }
  78. public void Dispose()
  79. {
  80. _objectRef.Free();
  81. }
  82. public bool IsMatch(object otherObject, MethodInfo otherMethod)
  83. {
  84. return WeakActionStructUtility.IsMatch(_objectRef.Target, _method,
  85. otherObject, otherMethod);
  86. }
  87. GCHandle _objectRef;
  88. readonly MethodInfo _method;
  89. }
  90. static class WeakActionStructUtility
  91. {
  92. internal static void Init(object target, MethodInfo method,
  93. out GCHandle objectRef, out MethodInfo methodOut)
  94. {
  95. objectRef = GCHandle.Alloc(target, GCHandleType.Weak);
  96. methodOut = method;
  97. #if DEBUG && !PROFILER
  98. #if NETFX_CORE
  99. Method = listener.GetMethodInfo();
  100. var attributes = (CompilerGeneratedAttribute[])Method.GetType().GetTypeInfo().GetCustomAttributes(typeof(CompilerGeneratedAttribute), false);
  101. if(attributes.Length != 0)
  102. throw new ArgumentException("Cannot create weak event to anonymous method with closure.");
  103. #else
  104. if (method.DeclaringType.GetCustomAttributes(typeof (CompilerGeneratedAttribute), false).Length != 0)
  105. throw new ArgumentException("Cannot create weak event to anonymous method with closure.");
  106. #endif
  107. #endif
  108. }
  109. public static bool Invoke(ref GCHandle objectRef, MethodInfo method, object[] args)
  110. {
  111. if (objectRef.IsAllocated && objectRef.Target != null)
  112. {
  113. method.Invoke(objectRef.Target, args);
  114. return true;
  115. }
  116. Dispose(ref objectRef);
  117. return false;
  118. }
  119. public static void Dispose(ref GCHandle objectRef)
  120. {
  121. objectRef.Free();
  122. }
  123. public static bool IsMatch(object objectRef, MethodInfo method,
  124. object _objectRef, MethodInfo _method)
  125. {
  126. return _method.Equals(method) && objectRef.Equals(_objectRef);
  127. }
  128. }
  129. }