Skip to content

Conversation

@pranavkm
Copy link

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.

Copy link
Member

@SteveSandersonMS SteveSandersonMS left a 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.

@pranavkm pranavkm marked this pull request as ready for review September 13, 2019 21:08
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.
@pranavkm pranavkm force-pushed the prkrishn/generic-jsinterop branch from 9e8001f to 098be37 Compare September 13, 2019 21:10
Copy link
Author

@pranavkm pranavkm left a 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}\")].");
Copy link
Author

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));
Copy link
Author

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>
Copy link
Author

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
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These scenarios throw ❌

@pranavkm pranavkm added this to the 3.1.0-preview2 milestone Sep 19, 2019
@pranavkm pranavkm merged commit 659b604 into release/3.1 Sep 19, 2019
@ghost ghost deleted the prkrishn/generic-jsinterop branch September 19, 2019 17:48
JunTaoLuo pushed a commit to dotnet/aspnetcore that referenced this pull request Feb 12, 2020
…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
JunTaoLuo pushed a commit to dotnet/aspnetcore that referenced this pull request Feb 15, 2020
…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
@ghost ghost locked as resolved and limited conversation to collaborators May 27, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants