-
Notifications
You must be signed in to change notification settings - Fork 23
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
Support free-form delegate signature #38
Comments
Hi @thomaslevesque , https://github.com/Matt90hz/WeakEventHandling This is how the open delegate is created. I think that is compatible with .netstandard1.3 (not sure 100%, but it should). public static WeakDelegate<TOwner, TParam1, TParam2> CreateOpenDelegate<TEventHandler, TOwner, TParam1, TParam2>(this TEventHandler eventHandler)
where TEventHandler : Delegate
where TOwner : class
{
try
{
return (WeakDelegate<TOwner, TParam1, TParam2>)Delegate.CreateDelegate(typeof(WeakDelegate<TOwner, TParam1, TParam2>), null, eventHandler.Method);
}
catch (Exception e)
{
throw new ArgumentException($"The event handler must be a void method with 2 parameters of type {typeof(TParam1).Name} and {typeof(TParam2).Name}.", nameof(eventHandler), e);
}
} I think it wouldn't be hard to adapt my code into yours. If you are interested in the idea I might give it a try in my spare time. |
Hi @Matt90hz, Thanks for the pointer! Actually, what I had in mind was something a bit more free-form than that. What you're suggesting isn't really free-form: for instance, the delegate can't have a non- TBH, I think the need for this is quite limited. The The approach used in the library requires knowing the delegate's shape, mostly for performance reasons. Supporting free-form delegated would require a lot of reflection and runtime code generation, which would negatively impact performance. So I don't think I will ever implement this... |
Mentioning this just made me think that we now have compile-time code generators in .NET, so maybe it would be possible to leverage that... |
Oh I see no restrictions what so ever. It would be pretty cool to implement, even if relatively useful as you pointed out. With code generators something like this can be definitely done: public partial class MyClass
{
private readonly FormFreeWeakEventSource<EventHandler<EventArgs>> _myEvent = new();
}
//Generated code
partial class MyClass
{
public event EventHandler<EventArgs> MyEvent
{
add
{
_myEvent.Subscribe(value);
}
remove
{
_myEvent.Unsubscribe(value);
}
}
} But at this point even an analyzer might do the trick. After all we just want to enforce the same delegate signature on the Been able to do this would be the real game changer imho: [WeakEvent]
public event AnyEventHandler MyEvent; But I don't know how to get there. Maybe with interceptors, if one day they will support more than just methods. I don't know maybe there is a better way. But I might try to code generate the weak event just for fun. |
Actually, the problematic part isn't really the event declaration with the The hard part is the open-instance delegate (see README). If I know the shape of the delegate statically, I can just declare the open-instance delegate explicitly in the code. But for a free-form delegate, I can't do that. Maybe I could generate the appropriate delegate type dynamically (which isn't trivial), but then I would have another problem: how to call it if I don't know its signature statically? It might be possible to generate the appropriate code based on usage; that's what I meant when I mentioned generators.
Yeah... unfortunately, for this to work, we would need to declare the event as |
You are right. I think that if there is some sort of marker for the code generation everything can be created dynamically. Given that the consumer of the library tolerates some boilerplate code. Something like this: // WeakFreeFormEventSource would be an empty class used just as a marker
partial class MyWeakEventSource : WeakFreeFormEventSource<WeirdHandler> { }
// Just any delegate it doesn't matter
public delegate int WeirdHandler(int a, int b);
public class Publisher
{
readonly MyWeakEventSource _weirdEvent = new();
public event WeirdHandler? WeirdEvent
{
add => _weirdEvent.Subscribe(value);
remove => _weirdEvent.Unsubscribe(value);
}
void OnWeirdEvent(int a, int b)
{
IEnumerable<int> results = _weirdEvent.Raise(a, b);
}
} And the generated code would be conceptually: // Generated
partial class MyWeakEventSource
{
delegate int OpenDelegate(object target, int arg1, int arg2);
readonly DelegateCollection _delegateCollection = new();
public void Subscribe(WeirdHandler? handler) { /* logic */ }
public void Unsubscribe(WeirdHandler? handler) { /* logic */ }
public IEnumerable<int> Raise(int a, int b) { /* logic */ }
} I think that this might be possible to achieve. A lot of the logic already written can also be reused. I have seen stuff like this done in some libraries, like OneOf. |
As opposed to being limited to
EventHandler<TEventArgs>
The text was updated successfully, but these errors were encountered: