Skip to content

Commit edd371c

Browse files
committed
Simplified the WeakEvent example.
1 parent c10782c commit edd371c

File tree

8 files changed

+63
-266
lines changed

8 files changed

+63
-266
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Runtime.CompilerServices;
4+
5+
namespace PostSharp.Samples.WeakEvent
6+
{
7+
internal static class DelegateReferenceKeeper
8+
{
9+
private static readonly object staticObj = new object();
10+
static readonly ConditionalWeakTable<object,List<Delegate>> table = new ConditionalWeakTable<object, List<Delegate>>();
11+
12+
public static void AddReference(Delegate handler)
13+
{
14+
List<Delegate> list = table.GetOrCreateValue(handler.Target ?? staticObj);
15+
lock (list)
16+
{
17+
list.Add(handler);
18+
}
19+
}
20+
21+
public static void RemoveReference(Delegate handler)
22+
{
23+
List<Delegate> list;
24+
if ( table.TryGetValue(handler.Target ?? staticObj, out list ) )
25+
{
26+
lock (list)
27+
{
28+
list.Remove(handler);
29+
}
30+
}
31+
}
32+
33+
}
34+
}

Framework/PostSharp.Samples.WeakEvent/IWeakEventClient.cs

Lines changed: 0 additions & 15 deletions
This file was deleted.

Framework/PostSharp.Samples.WeakEvent/PostSharp.Samples.WeakEvent.csproj

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,11 @@
5757
<Reference Include="System.Xml" />
5858
</ItemGroup>
5959
<ItemGroup>
60-
<Compile Include="IWeakEventClient.cs" />
60+
<Compile Include="DelegateReferenceKeeper.cs" />
6161
<Compile Include="Program.cs" />
6262
<Compile Include="Properties\AssemblyInfo.cs" />
6363
<Compile Include="WeakEventAttribute.cs" />
64-
<Compile Include="WeakEventClientAttribute.cs" />
6564
<Compile Include="WeakEventHandler.cs" />
66-
<Compile Include="WeakEventValidation.cs" />
6765
</ItemGroup>
6866
<ItemGroup>
6967
<None Include="App.config" />

Framework/PostSharp.Samples.WeakEvent/Program.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,27 @@ private static void Main(string[] args)
1414

1515
// Raise the event when the client is alive.
1616
MyEvent(null, EventArgs.Empty);
17-
Console.WriteLine("EventHandlerCount: {0}", EventClient.EventHandlerCount); // Should be 1.
17+
Console.WriteLine("EventHandlerCount: {0} (should be 1)", EventClient.EventHandlerCount);
1818

1919

2020
// Cause the client to be collected.
2121
var weakReference = new WeakReference(eventClient);
2222
eventClient = null;
2323
GC.Collect();
2424

25-
Console.WriteLine("Client is alive: {0}", weakReference.IsAlive); // Should be False.
26-
27-
25+
Console.WriteLine("Client is alive: {0} (should be False)", weakReference.IsAlive);
26+
27+
2828
// Raise the event when the client is dead.
29+
EventClient.EventHandlerCount = 0;
2930
MyEvent(null, EventArgs.Empty);
30-
Console.WriteLine("EventHandlerCount: {0}", EventClient.EventHandlerCount); // Should be 1.
31+
Console.WriteLine("EventHandlerCount: {0} (should be 0)", EventClient.EventHandlerCount);
3132
}
3233

3334
[WeakEvent]
3435
private static event EventHandler MyEvent;
3536
}
3637

37-
[WeakEventClient]
3838
internal class EventClient
3939
{
4040
public static int EventHandlerCount;

Framework/PostSharp.Samples.WeakEvent/WeakEventAttribute.cs

Lines changed: 10 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -14,31 +14,11 @@ namespace PostSharp.Samples.WeakEvent
1414
/// </summary>
1515
[PSerializable]
1616
[LinesOfCodeAvoided(6)]
17-
[WeakEventValidation]
1817
public sealed class WeakEventAttribute : EventInterceptionAspect, IInstanceScopedAspect
1918
{
2019
[PNonSerialized] private WeakEventHandler weakEventHandler;
2120

2221

23-
/// <summary>
24-
/// Initializes a new <see cref="WeakEventAttribute" />
25-
/// </summary>
26-
/// <param name="allowStrongReferences">
27-
/// Determines whether the current aspect is allowed to create a strong reference if the client does not have
28-
/// the <see cref="WeakEventClientAttribute" /> aspect. The default value is <c>false</c>.
29-
/// </param>
30-
public WeakEventAttribute(bool allowStrongReferences = false)
31-
{
32-
AllowStrongReferences = allowStrongReferences;
33-
}
34-
35-
/// <summary>
36-
/// Determines whether the current aspect is allowed to create a strong reference if the client does not have
37-
/// the <see cref="WeakEventClientAttribute" /> aspect.
38-
/// </summary>
39-
public bool AllowStrongReferences { get; set; }
40-
41-
4222
/// <summary>
4323
/// Creates an instance of the aspect for a specific instance of the target class (when the target event is not
4424
/// static). A call of this method is followed by a call of RuntimeInitializeInstance.
@@ -73,31 +53,19 @@ public override void RuntimeInitialize(EventInfo eventInfo)
7353
/// <param name="args">Context information.</param>
7454
public override void OnAddHandler(EventInterceptionArgs args)
7555
{
76-
var weakEventClient = args.Handler.Target as IWeakEventClient;
77-
var supportsWeakReference = weakEventClient != null;
78-
79-
// Throw an exception if the client does not support weak events and we are not allowed to hold strong references.
80-
if (!supportsWeakReference && args.Handler.Target != null && !AllowStrongReferences)
81-
{
82-
throw new InvalidOperationException(
83-
string.Format(
84-
"Attempt to add a reference to the weak event {0} from type {1}, which does not implement the IWeakEventClient interface.",
85-
args.Event, args.Handler.Target.GetType()));
86-
}
56+
8757

8858
// Add the handler to our own list.
89-
if (weakEventHandler.AddHandler(args.Handler, supportsWeakReference))
59+
if (weakEventHandler.AddHandler(args.Handler))
9060
{
9161
// If it is the first handler we are adding, add a fake handler to ourselves to the target event.
9262
// Whichever handler will add here will be passed to OnInvokeHandler, so it is safe and convenient to pass null.
9363
args.AddHandler(null);
94-
}
95-
64+
}
65+
66+
9667
// Register the handler to the client to prevent garbage collection of the handler.
97-
if (supportsWeakReference)
98-
{
99-
weakEventClient.RegisterEventHandler(args.Handler);
100-
}
68+
DelegateReferenceKeeper.AddReference(args.Handler);
10169
}
10270

10371
/// <summary>
@@ -106,22 +74,15 @@ public override void OnAddHandler(EventInterceptionArgs args)
10674
/// <param name="args">Context information.</param>
10775
public override void OnRemoveHandler(EventInterceptionArgs args)
10876
{
109-
var weakEventClient = args.Handler.Target as IWeakEventClient;
110-
111-
var supportsWeakReference = weakEventClient != null;
112-
113-
// Remove the handler from our own list.
77+
// Remove the handler from our own list.
11478
if (weakEventHandler.RemoveHandler(args.Handler))
11579
{
11680
// If this is the last handler, remove the fake handler to ourselves from the target event.
11781
args.RemoveHandler(null);
118-
}
119-
82+
}
83+
12084
// Remove the handler from the client.
121-
if (supportsWeakReference)
122-
{
123-
weakEventClient.UnregisterEventHandler(args.Handler);
124-
}
85+
DelegateReferenceKeeper.RemoveReference(args.Handler);
12586
}
12687

12788
/// <summary>

Framework/PostSharp.Samples.WeakEvent/WeakEventClientAttribute.cs

Lines changed: 0 additions & 77 deletions
This file was deleted.

Framework/PostSharp.Samples.WeakEvent/WeakEventHandler.cs

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
namespace PostSharp.Samples.WeakEvent
99
{
10-
[PSerializable]
1110
internal struct WeakEventHandler
1211
{
1312
private bool initialized;
@@ -25,15 +24,15 @@ public void Initialize()
2524
}
2625
}
2726

28-
public bool AddHandler(Delegate handler, bool weak)
27+
public bool AddHandler(Delegate handler)
2928
{
3029
var lockTaken = false;
3130

3231
try
3332
{
3433
spinLock.Enter(ref lockTaken);
3534

36-
handlers = handlers.Add(weak ? (object) new WeakReference(handler) : handler);
35+
handlers = handlers.Add(new WeakReference(handler));
3736

3837
return handlers.Length == 1;
3938
}
@@ -55,9 +54,7 @@ public bool RemoveHandler(Delegate handler)
5554

5655
handlers =
5756
handlers.RemoveAll(
58-
o =>
59-
ReferenceEquals(o, handler) ||
60-
o is WeakReference && ReferenceEquals(((WeakReference) o).Target, handler));
57+
o => ReferenceEquals(((WeakReference) o).Target, handler));
6158

6259
return handlers.IsEmpty;
6360
}
@@ -83,24 +80,20 @@ public void InvokeHandler(object[] args)
8380

8481
foreach (var obj in invocationList)
8582
{
86-
var handler = obj as Delegate;
83+
84+
var handler = (Delegate) ((WeakReference) obj).Target;
8785

8886
if (handler == null)
8987
{
90-
handler = (Delegate) ((WeakReference) obj).Target;
91-
92-
if (handler == null)
88+
if (!needCleanUp)
9389
{
94-
if (!needCleanUp)
95-
{
96-
needCleanUp = true;
97-
lastCleanUpCounter = cleanUpCounter;
98-
}
99-
100-
continue;
90+
needCleanUp = true;
91+
lastCleanUpCounter = cleanUpCounter;
10192
}
102-
}
10393

94+
continue;
95+
}
96+
10497

10598
handler.DynamicInvoke(args);
10699
}
@@ -113,7 +106,7 @@ public void InvokeHandler(object[] args)
113106
try
114107
{
115108
spinLock.Enter(ref lockTaken);
116-
handlers = handlers.RemoveAll(w => w is WeakReference && !((WeakReference) w).IsAlive);
109+
handlers = handlers.RemoveAll(w => !((WeakReference) w).IsAlive);
117110

118111
Interlocked.Increment(ref cleanUpCounter);
119112
}

0 commit comments

Comments
 (0)