Skip to content

Commit

Permalink
Merge pull request #293 from AArnott/fix292
Browse files Browse the repository at this point in the history
Fix support for target object events with certain generic delegates
  • Loading branch information
AArnott authored Jun 20, 2019
2 parents 9b2d637 + e8ab5da commit b836f6c
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 3 deletions.
28 changes: 28 additions & 0 deletions src/StreamJsonRpc.Tests/TargetObjectEventsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,17 @@ public async Task GenericServerEventRaisesCallback()
Assert.Equal(expectedArgs.Seeds, actualArgs.Seeds);
}

[Fact]
public async Task CustomDelegateServerEventRaisesCallback()
{
var tcs = new TaskCompletionSource<MessageEventArgs<string>>();
var expectedArgs = new MessageEventArgs<string> { Message = "a" };
this.client.ServerEventWithCustomGenericDelegateAndArgsRaised = args => tcs.SetResult(args);
this.server.TriggerServerEventWithCustomGenericDelegateAndArgs(expectedArgs);
var actualArgs = await tcs.Task.WithCancellation(this.TimeoutToken);
Assert.Equal<string>(expectedArgs.Message, actualArgs.Message);
}

/// <summary>
/// Verifies that events on target objects are subscribed to, and unsubscribed after the JsonRpc instance is disposed of.
/// </summary>
Expand Down Expand Up @@ -201,21 +212,29 @@ private class Client

internal Action<CustomEventArgs> GenericServerEventRaised { get; set; }

internal Action<MessageEventArgs<string>> ServerEventWithCustomGenericDelegateAndArgsRaised { get; set; }

public void ServerEvent(EventArgs args) => this.ServerEventRaised?.Invoke(args);

public void PublicStaticServerEvent(EventArgs args) => this.PublicStaticServerEventRaised?.Invoke(args);

public void ServerEventWithCustomArgs(CustomEventArgs args) => this.GenericServerEventRaised?.Invoke(args);

public void ServerEventWithCustomGenericDelegateAndArgs(MessageEventArgs<string> args) => this.ServerEventWithCustomGenericDelegateAndArgsRaised?.Invoke(args);
}

private class Server
{
public delegate void MessageReceivedEventHandler<T>(object sender, MessageEventArgs<T> args);

public static event EventHandler PublicStaticServerEvent;

public event EventHandler ServerEvent;

public event EventHandler<CustomEventArgs> ServerEventWithCustomArgs;

public event MessageReceivedEventHandler<string> ServerEventWithCustomGenericDelegateAndArgs;

private static event EventHandler PrivateStaticServerEvent;

private event EventHandler PrivateServerEvent;
Expand All @@ -236,13 +255,17 @@ public void TriggerGenericEvent(CustomEventArgs args)
this.OnServerEventWithCustomArgs(args);
}

public void TriggerServerEventWithCustomGenericDelegateAndArgs(MessageEventArgs<string> args) => this.OnServerEventWithCustomGenericDelegateAndArgs(args);

protected static void OnPrivateStaticServerEvent(EventArgs args) => PrivateStaticServerEvent?.Invoke(null, args);

protected virtual void OnServerEvent(EventArgs args) => this.ServerEvent?.Invoke(this, args);

protected virtual void OnServerEventWithCustomArgs(CustomEventArgs args) => this.ServerEventWithCustomArgs?.Invoke(this, args);

protected virtual void OnPrivateServerEvent(EventArgs args) => this.PrivateServerEvent?.Invoke(this, args);

protected virtual void OnServerEventWithCustomGenericDelegateAndArgs(MessageEventArgs<string> args) => this.ServerEventWithCustomGenericDelegateAndArgs?.Invoke(this, args);
}

private class ServerWithIncompatibleEvents
Expand All @@ -258,4 +281,9 @@ private class CustomEventArgs : EventArgs
{
public int Seeds { get; set; }
}

private class MessageEventArgs<T> : EventArgs
{
public T Message { get; set; }
}
}
12 changes: 9 additions & 3 deletions src/StreamJsonRpc/JsonRpc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2007,14 +2007,20 @@ internal EventReceiver(JsonRpc jsonRpc, object server, EventInfo eventInfo, Json
// It will work for EventHandler and EventHandler<T>, at least.
// If we want to support more, we'll likely have to use lightweight code-gen to generate a method
// with the right signature.
if (eventInfo.EventHandlerType.Equals(typeof(EventHandler)))
var eventHandlerParameters = eventInfo.EventHandlerType.GetTypeInfo().GetMethod("Invoke").GetParameters();
if (eventHandlerParameters.Length != 2)
{
throw new NotSupportedException($"Unsupported event handler type for: \"{eventInfo.Name}\". Expected 2 parameters but had {eventHandlerParameters.Length}.");
}

Type argsType = eventHandlerParameters[1].ParameterType;
if (typeof(EventArgs).GetTypeInfo().IsAssignableFrom(argsType))
{
this.registeredHandler = OnEventRaisedMethodInfo.CreateDelegate(eventInfo.EventHandlerType, this);
}
else
{
Type eventArgsType = eventInfo.EventHandlerType.GenericTypeArguments.FirstOrDefault() ?? typeof(object);
var closedGenericMethod = OnEventRaisedGenericMethodInfo.MakeGenericMethod(eventArgsType);
var closedGenericMethod = OnEventRaisedGenericMethodInfo.MakeGenericMethod(argsType);
this.registeredHandler = closedGenericMethod.CreateDelegate(eventInfo.EventHandlerType, this);
}
}
Expand Down

0 comments on commit b836f6c

Please sign in to comment.