Monitored event with a return type throws InvalidProgramException after invocation
See original GitHub issueDescription
If you create monitor for any type with an event that has a return type, and then invoke that event, it will throw InvalidProgramException
.
Issue reproduces on events with parameters and without it, with reference return type and with value return type.
Looks like it’s happens because EventHandlerFactory.GenerateHandler()
can’t create delegate with a return type. If you take a closer look, you can see that stack is empty when Ret instruction is called, I’m not sure about this, but look like it’s a reason of this issue. For testing i added ilGen.Emit(OpCodes.Ldc_I4_1);
before Ret instruction and exception was not thrown, and event return True.
Complete minimal example reproducing the issue
public class Tests
{
[Test]
public void FollowingCausesError()
{
var target = new Subject();
using (var monitor = target.Monitor())
{
target.Invoke();
}
}
}
class Subject
{
public void Invoke()
{
Target?.Invoke();
}
public event Func<bool> Target;
}
Expected behavior:
Throw an exception on AssertionExtension.Monitor()
invocation with message like “Can’t create monitor for event {eventName} because it has a return value” (and add a description for this to documentation).
Actual behavior:
Throws an InvalidProgramException after target.Invoke()
with following message:
System.InvalidProgramException : Common Language Runtime detected an invalid program.
at Func`2DynamicHandler(IEventRecorder , Int32 )
at FailureDemo.Subject.Invoke(Int32 i) in C:\Users\uvaro\RiderProjects\FailureDemo\UnitTest1.cs:line 24
at FailureDemo.Tests.FollowingCausesError() in C:\Users\uvaro\RiderProjects\FailureDemo\UnitTest1.cs:line 15
Versions
Reproduced on .NET Core 3.1 and .NET Framework 4.8 with Fluent Assertions v5.10.3
Issue Analytics
- State:
- Created 3 years ago
- Comments:5 (3 by maintainers)
Top GitHub Comments
You misunderstood me. We’re not planning to support anything but the official Microsoft guideline. If you use an
event
, you’re supposed to use theEventArgs
sub-class to share data with all the subscribers. But returning data from the subscriber back to the code that raises is it, is tricky at best. You have no control on how many subscribers you have. That’s why events have lost their popularity and people often switch to callback constructions likeAction
andFunc
.Well, the best we can do is to try to handle unexpected exceptions a bit better, but considering the complexity of the generation code, it’s going to be hard. Plus, it’s quite weird to use
Func<bool>
andevent
at the same time.