-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[EventListener] We should add a new method ListenEvents()
#38804
Comments
I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label. |
ListenerEvents()
ListenEvents()
@John0King - Thanks for the suggestion! I agree that callbacks running before the derived constructor runs is confusing. I suspect the largest challenge here is how to handle back-compat. We wouldn't want to make a change that causes existing code which doesn't call ListenEvents() to stop working. Let me know if you have any thoughts on how we could address that problem? |
Yes, the challenge is back-compat.
because the event do we still need to create our child class? why not create a static method |
If I had to choose between breaking changes and not running the constructor beforehand I would consider not running the constructor to be the lesser evil. Unfortunately the options 1-4 don't appear to avoid the breaking changes - 2 and 4 accept them directly, 1 is breaking if the retargeting applies to any code automatically, and 3 is breaking for any events that would have otherwise been delivered before the timer expires. CreateEventListener() could be done without a breaking change but down that road seems to be ignoring the existing API and starting over? New API design is an involved process and new/alternate variations of old APIs add complexity. Sometimes it is justified but this issue doesn't appear problematic enough yet that we'd want to do that. As a potential workaround you could write something like this?
Derived class constructors are run after the base class, but initializers are run beforehand. Sorry it may not be as satisfying as an updated API but hopefully it helps? |
Possible API 5partial class EventListener
{
// Change the existing constructor to call the new one.
protected EventListener() : this(listen: true) {}
// Calls ListenEvents if listen == true.
protected EventListener(bool listen);
// Calls OnEventSourceCreated for existing event sources
// and starts calling it for future event sources.
// Throws InvalidOperationException if ListenEvents has
// already been called, because that suggests the earlier
// call was made before initialization was complete.
// Throws ObjectDisposedException if Dispose has been called.
protected void ListenEvents();
} Usage: public class SimpleEventListener : EventListener
{
private readonly int _intervalSec;
public SimpleEventListener() : base(listen: false)
{
_intervalSec = 1;
this.ListenEvents();
}
protected override void OnEventSourceCreated(EventSource source)
{
var a = _internalSec; // is reliably 1
}
} However, if you wanted to offer the same capability to classes derived from public SimpleEventListener(bool listen) : base(listen: false)
{
_intervalSec = 1;
if (listen)
{
this.ListenEvents();
}
} Bad API 6partial class EventListener
{
protected virtual void ListenEvents(); // called by constructor
} Usage: public class SimpleEventListener : EventListener
{
private int _intervalSec; // now cannot be readonly
public SimpleEventListener()
{
}
protected override void ListenEvents()
{
_intervalSec = 1; // set here, not in constructor
base.ListenEvents();
}
protected override void OnEventSourceCreated(EventSource source)
{
var a = _internalSec; // is reliably 1
}
} However, if you wanted to add a |
@KalleOlaviNiemitalo - thanks for the suggestion! I haven't scrutinized in detail but 'Possible API 5' looks like a pretty reasonable solution to me. It keeps complexity fairly low, largely reuses the existing API, and has no apparent breaking changes. |
personally, I think auto listen in constructor is not a good idea, I'd like the here's my suggestion:
|
It appears to me that the only way to use Can this approach be documented? I have spent the better part of a day just trying to figure out how to use |
Moving older issues to the Future milestone as it is unlikely we will have time to address this in the .NET 7 timeframe. Please feel free to move this issue back to .NET 7 if there is active work to address the feature request. |
@tommcdon what's your suggestion for using the |
For anyone using EventListener in 7.0 (or any earlier release since it was first created) I'd suggest:
|
Primary constructors come to the rescue along with @noahfalk's approach using fields initializer: class SimpleEventListener(int intervalSec) : EventListener
{
private readonly int _intervalSec = intervalSec;
protected override void OnEventSourceCreated(EventSource eventSource)
{
Debug.Assert(_intervalSec == intervalSec);
base.OnEventSourceCreated(eventSource);
}
} Or just reference primary constructor parameter (intervalSec) directly in the |
Description
when I looking this doc https://github.com/dotnet/diagnostics/blob/master/documentation/design-docs/eventcounters.md#sample-code, I find that there is a private field in the construct that this sample code do not use,
after I "correct" the code , the
SimpleEventListener
won't work. After debug , I find that the methodOnEventSourceCreated
called before the constructor code, and this is caused by the the base constructor eg.EventCounter()/base()
were doing all the work to callOnEventSourceCreated
, and the only way to fix is to use eventEventSourceCreated
.this behavior is against the normal code execution, that constructor should run first , and cause error behaviors for
private readonly field
so I think we should add a new method
ListenEvents()
, to start listen after the instance being createdThe text was updated successfully, but these errors were encountered: