diff --git a/src/StreamJsonRpc.Tests/TargetObjectEventsTests.cs b/src/StreamJsonRpc.Tests/TargetObjectEventsTests.cs index 272823cb..30d804f6 100644 --- a/src/StreamJsonRpc.Tests/TargetObjectEventsTests.cs +++ b/src/StreamJsonRpc.Tests/TargetObjectEventsTests.cs @@ -93,6 +93,17 @@ public async Task GenericServerEventRaisesCallback() Assert.Equal(expectedArgs.Seeds, actualArgs.Seeds); } + [Fact] + public async Task CustomDelegateServerEventRaisesCallback() + { + var tcs = new TaskCompletionSource>(); + var expectedArgs = new MessageEventArgs { Message = "a" }; + this.client.ServerEventWithCustomGenericDelegateAndArgsRaised = args => tcs.SetResult(args); + this.server.TriggerServerEventWithCustomGenericDelegateAndArgs(expectedArgs); + var actualArgs = await tcs.Task.WithCancellation(this.TimeoutToken); + Assert.Equal(expectedArgs.Message, actualArgs.Message); + } + /// /// Verifies that events on target objects are subscribed to, and unsubscribed after the JsonRpc instance is disposed of. /// @@ -201,21 +212,29 @@ private class Client internal Action GenericServerEventRaised { get; set; } + internal Action> 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 args) => this.ServerEventWithCustomGenericDelegateAndArgsRaised?.Invoke(args); } private class Server { + public delegate void MessageReceivedEventHandler(object sender, MessageEventArgs args); + public static event EventHandler PublicStaticServerEvent; public event EventHandler ServerEvent; public event EventHandler ServerEventWithCustomArgs; + public event MessageReceivedEventHandler ServerEventWithCustomGenericDelegateAndArgs; + private static event EventHandler PrivateStaticServerEvent; private event EventHandler PrivateServerEvent; @@ -236,6 +255,8 @@ public void TriggerGenericEvent(CustomEventArgs args) this.OnServerEventWithCustomArgs(args); } + public void TriggerServerEventWithCustomGenericDelegateAndArgs(MessageEventArgs 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); @@ -243,6 +264,8 @@ public void TriggerGenericEvent(CustomEventArgs 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 args) => this.ServerEventWithCustomGenericDelegateAndArgs?.Invoke(this, args); } private class ServerWithIncompatibleEvents @@ -258,4 +281,9 @@ private class CustomEventArgs : EventArgs { public int Seeds { get; set; } } + + private class MessageEventArgs : EventArgs + { + public T Message { get; set; } + } } diff --git a/src/StreamJsonRpc/JsonRpc.cs b/src/StreamJsonRpc/JsonRpc.cs index a882e09f..da40a4b1 100644 --- a/src/StreamJsonRpc/JsonRpc.cs +++ b/src/StreamJsonRpc/JsonRpc.cs @@ -2007,14 +2007,20 @@ internal EventReceiver(JsonRpc jsonRpc, object server, EventInfo eventInfo, Json // It will work for EventHandler and EventHandler, 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); } }