using System; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; //careful, you must handle the destruction of the GCHandles! namespace Svelto.WeakEvents { public struct WeakActionStruct : IEquatable>, IDisposable { public WeakActionStruct(Action listener) { WeakActionStructUtility.Init(listener.Target, listener.GetMethodInfoEx(), out _objectRef, out _method); } public bool Invoke(object[] args) { return WeakActionStructUtility.Invoke(ref _objectRef, _method, args); } public bool Equals(WeakActionStruct other) { return WeakActionStructUtility.IsMatch(_objectRef.Target, _method, other._objectRef.Target, other._method); } public void Dispose() { _objectRef.Free(); } public bool IsMatch(object otherObject, MethodInfo otherMethod) { return WeakActionStructUtility.IsMatch(_objectRef.Target, _method, otherObject, otherMethod); } GCHandle _objectRef; readonly MethodInfo _method; } public struct WeakActionStruct : IEquatable>, IDisposable { public WeakActionStruct(Action listener) { WeakActionStructUtility.Init(listener.Target, listener.GetMethodInfoEx(), out _objectRef, out _method); } public bool Invoke(object[] args) { return WeakActionStructUtility.Invoke(ref _objectRef, _method, args); } public bool Equals(WeakActionStruct other) { return WeakActionStructUtility.IsMatch(_objectRef.Target, _method, other._objectRef.Target, other._method); } public void Dispose() { _objectRef.Free(); } public bool IsMatch(object otherObject, MethodInfo otherMethod) { return WeakActionStructUtility.IsMatch(_objectRef.Target, _method, otherObject, otherMethod); } GCHandle _objectRef; readonly MethodInfo _method; } public struct WeakActionStruct : IEquatable, IDisposable { public WeakActionStruct(Action listener) { WeakActionStructUtility.Init(listener.Target, listener.GetMethodInfoEx(), out _objectRef, out _method); } public bool Invoke() { return WeakActionStructUtility.Invoke(ref _objectRef, _method, null); } public bool Equals(WeakActionStruct other) { return WeakActionStructUtility.IsMatch(_objectRef.Target, _method, other._objectRef.Target, other._method); } public void Dispose() { _objectRef.Free(); } public bool IsMatch(object otherObject, MethodInfo otherMethod) { return WeakActionStructUtility.IsMatch(_objectRef.Target, _method, otherObject, otherMethod); } GCHandle _objectRef; readonly MethodInfo _method; } static class WeakActionStructUtility { internal static void Init(object target, MethodInfo method, out GCHandle objectRef, out MethodInfo methodOut) { objectRef = GCHandle.Alloc(target, GCHandleType.Weak); methodOut = method; #if DEBUG && !PROFILER #if NETFX_CORE Method = listener.GetMethodInfo(); var attributes = (CompilerGeneratedAttribute[])Method.GetType().GetTypeInfo().GetCustomAttributes(typeof(CompilerGeneratedAttribute), false); if(attributes.Length != 0) throw new ArgumentException("Cannot create weak event to anonymous method with closure."); #else if (method.DeclaringType.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Length != 0) throw new ArgumentException("Cannot create weak event to anonymous method with closure."); #endif #endif } public static bool Invoke(ref GCHandle objectRef, MethodInfo method, object[] args) { if (objectRef.IsAllocated && objectRef.Target != null) { method.Invoke(objectRef.Target, args); return true; } Dispose(ref objectRef); return false; } public static void Dispose(ref GCHandle objectRef) { objectRef.Free(); } public static bool IsMatch(object objectRef, MethodInfo method, object _objectRef, MethodInfo _method) { return _method.Equals(method) && objectRef.Equals(_objectRef); } } }