Skip to content

Commit

Permalink
Merge pull request #1793 from hermestobias/master
Browse files Browse the repository at this point in the history
Quite possibly the best performance based PR ever received. Thank you so much for your effort.
  • Loading branch information
brianlagunas committed May 24, 2019
2 parents 381d56c + 2aa53df commit eccb6e3
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 10 deletions.
47 changes: 47 additions & 0 deletions Source/Prism.Tests/Events/DelegateReferenceFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,53 @@ public void WeakDelegateWorksWithStaticMethodDelegates()
Assert.NotNull(action.Target);
}

[Fact]
public void TargetEqualsActionShouldReturnTrue()
{
var classHandler = new SomeClassHandler();
Action<string> myAction = new Action<string>(classHandler.MyAction);

var weakAction = new DelegateReference(myAction, false);

Assert.True(weakAction.TargetEquals(new Action<string>(classHandler.MyAction)));
}

[Fact]
public void TargetEqualsNullShouldReturnTrueIfTargetNotAlive()
{
SomeClassHandler handler = new SomeClassHandler();
var weakHandlerRef = new WeakReference(handler);

var action = new DelegateReference((Action<string>)handler.DoEvent, false);

handler = null;
GC.Collect();
Assert.False(weakHandlerRef.IsAlive);

Assert.True(action.TargetEquals(null));
}

[Fact]
public void TargetEqualsNullShouldReturnFalseIfTargetAlive()
{
SomeClassHandler handler = new SomeClassHandler();
var weakHandlerRef = new WeakReference(handler);

var action = new DelegateReference((Action<string>)handler.DoEvent, false);

Assert.False(action.TargetEquals(null));
Assert.True(weakHandlerRef.IsAlive);
GC.KeepAlive(handler);
}

[Fact]
public void TargetEqualsWorksWithStaticMethodDelegates()
{
var action = new DelegateReference((Action)SomeClassHandler.StaticMethod, false);

Assert.True(action.TargetEquals((Action)SomeClassHandler.StaticMethod));
}

//todo: fix
//[Fact]
//public void NullDelegateThrows()
Expand Down
23 changes: 21 additions & 2 deletions Source/Prism/Events/DelegateReference.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public DelegateReference(Delegate @delegate, bool keepReferenceAlive)
_delegateType = @delegate.GetType();
}
}

/// <summary>
/// Gets the <see cref="Delegate" /> (the target) referenced by the current <see cref="DelegateReference"/> object.
/// </summary>
Expand All @@ -59,7 +59,26 @@ public Delegate Target
}
}
}


/// <summary>
/// Checks if the <see cref="Delegate" /> (the target) referenced by the current <see cref="DelegateReference"/> object are equal to another <see cref="Delegate" />.
/// This is equivalent with comparing <see cref="Target"/> with <paramref name="delegate"/>, only more efficient.
/// </summary>
/// <param name="delegate">The other delegate to compare with.</param>
/// <returns>True if the target referenced by the current object are equal to <paramref name="delegate"/>.</returns>
public bool TargetEquals(Delegate @delegate)
{
if (_delegate != null)
{
return _delegate == @delegate;
}
if (@delegate == null)
{
return !_method.IsStatic && !_weakReference.IsAlive;
}
return _weakReference.Target == @delegate.Target && Equals(_method, @delegate.GetMethodInfo());
}

private Delegate TryGetDelegate()
{
if (_method.IsStatic)
Expand Down
12 changes: 4 additions & 8 deletions Source/Wpf/Prism.Wpf/Events/WeakDelegatesManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,15 @@ public void AddListener(Delegate listener)

public void RemoveListener(Delegate listener)
{
this.listeners.RemoveAll(reference =>
{
//Remove the listener, and prune collected listeners
Delegate target = reference.Target;
return listener.Equals(target) || target == null;
});
//Remove the listener, and prune collected listeners
this.listeners.RemoveAll(reference => reference.TargetEquals(null) || reference.TargetEquals(listener));
}

public void Raise(params object[] args)
{
this.listeners.RemoveAll(listener => listener.Target == null);
this.listeners.RemoveAll(listener => listener.TargetEquals(null));

foreach (Delegate handler in this.listeners.ToList().Select(listener => listener.Target).Where(listener => listener != null))
foreach (Delegate handler in this.listeners.Select(listener => listener.Target).Where(listener => listener != null).ToList())
{
handler.DynamicInvoke(args);
}
Expand Down

0 comments on commit eccb6e3

Please sign in to comment.