-
Notifications
You must be signed in to change notification settings - Fork 849
Add support for JSInvokable methods on generic types #2342
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
Conversation
SteveSandersonMS
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks perfect to me, and also fixes #1360 at the same time.
Prior to this change, DotNetDispatcher cached the MethodInfo on the generic type definition. Using this would have required MethodInfo.MakeGenericMethod before the method was invoked. We could separately cache the result of this to avoid the reflection cost per invocation. Alternatively we could cache static and non-static MethodInfo instances separately which is what this change attempts to do. The big difference in the outcome is that this requires instance (non-static) JSInvokable methods to be only unique named within the type hierarchy as opposed to across all static and instance JSInvokable methods in an assembly.
9e8001f to
098be37
Compare
pranavkm
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added some tests for open generic methods.
| } | ||
| else | ||
| { | ||
| throw new ArgumentException($"The type '{type.Name}' does not contain a public invokable method with [{nameof(JSInvokableAttribute)}(\"{methodIdentifier}\")]."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would exposing the type name be problematic in any way? For instance methods, reporting the object id isn't useful.
| BindingFlags.Static)) | ||
| .Where(method => method.IsDefined(typeof(JSInvokableAttribute), inherit: false)); | ||
| .SelectMany(type => type.GetMethods(BindingFlags.Public | BindingFlags.Static)) | ||
| .Where(method => !method.ContainsGenericParameters && method.IsDefined(typeof(JSInvokableAttribute), inherit: false)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to https://docs.microsoft.com/en-us/dotnet/api/system.reflection.methodbase.containsgenericparameters?view=netframework-4.8, methods containing generic parameters cannot be invoked:
If the ContainsGenericParameters property returns true, the method cannot be invoked.
This gives us the opportunity to treat these pretty much the same as non-public methods with JsInvokable and provide a more meaningful message. Without this check, you get strange errors from System.Text.Json.
| } | ||
| } | ||
|
|
||
| public class GenericType<TValue> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These scenarios work ✔️
| [JSInvokable] public TValue EchoParameter(TValue input) => input; | ||
| } | ||
|
|
||
| public class GenericMethodClass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These scenarios throw ❌
…ns#2342) * Add support for JSInvokable methods on generic types Prior to this change, DotNetDispatcher cached the MethodInfo on the generic type definition. Using this would have required MethodInfo.MakeGenericMethod before the method was invoked. We could separately cache the result of this to avoid the reflection cost per invocation. Alternatively we could cache static and non-static MethodInfo instances separately which is what this change attempts to do. The big difference in the outcome is that this requires instance (non-static) JSInvokable methods to be only unique named within the type hierarchy as opposed to across all static and instance JSInvokable methods in an assembly. Fixes dotnet/extensions#1360 Fixes #9061 \n\nCommit migrated from dotnet/extensions@659b604
…ns#2342) * Add support for JSInvokable methods on generic types Prior to this change, DotNetDispatcher cached the MethodInfo on the generic type definition. Using this would have required MethodInfo.MakeGenericMethod before the method was invoked. We could separately cache the result of this to avoid the reflection cost per invocation. Alternatively we could cache static and non-static MethodInfo instances separately which is what this change attempts to do. The big difference in the outcome is that this requires instance (non-static) JSInvokable methods to be only unique named within the type hierarchy as opposed to across all static and instance JSInvokable methods in an assembly. Fixes dotnet/extensions#1360 Fixes #9061 \n\nCommit migrated from dotnet/extensions@659b604
Prior to this change, DotNetDispatcher cached the MethodInfo on the
generic type definition. Using this would have required MethodInfo.MakeGenericMethod before the method was invoked.
We could separately cache the result of this to avoid the reflection cost per invocation.
Alternatively we could cache static and non-static MethodInfo instances separately which is what this change attempts to do.
The big difference in the outcome is that this requires instance (non-static) JSInvokable methods to be only unique named within
the type hierarchy as opposed to across all static and instance JSInvokable methods in an assembly.