mercredi 25 août 2021

How can I call a generic delegate?

I'm not very proficient in C#, so please bear with me.

I tried to make my code as simple as possible to outline my problem.

This is code from an external library I have no control over:

public class Library {

    public delegate void Handler<T>(in T type);

    public void Subscribe<T>(Handler<T> handler) {
        // Whatever...
    }

}

This is my application code:

public class Application {

    public void Run() {
        var library = new Library();
        var types = new List<Type>() {typeof(int), typeof(string)};
        foreach(var type in types) {
            var methodLibrary = library.GetType().GetMethod("Subscribe");
            var methodLibraryGeneric = methodLibrary.MakeGenericMethod(new Type[] {type});
            var methodApplication = this.GetType().GetMethod("OnHandler", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
            var methodApplicationGeneric = methodApplication.MakeGenericMethod(new Type[] {type});

            // [EXCEPTION] System.ArgumentException: method arguments are incompatible
            var delegateApplication = Delegate.CreateDelegate(typeof(Library.Handler<>), methodApplicationGeneric);

            methodLibraryGeneric.Invoke(library, new object[] {delegateApplication});
        }
    }

    private void OnHandler<T>(in T type) {
        // Whatever...
    }

}

I hope it's clear what I'm trying to do: I have a whole bunch of types I determine at runtime (not just int/string for demo purposes), and I want all of them to be registered with the external library which calls back into my code.

As a workaround I could explicitly call library.Subscribe<int>(OnHandler) for each and every type, but that would be rather brittle and error-prone, and I thought generics could help.

If I'm doing something incredibly stupid, just tell me-- preferably including a more elegant solution than hard-coding the subscription for each and every type. :)

Any help appreciated.





Aucun commentaire:

Enregistrer un commentaire