@@ -13,14 +13,12 @@ namespace Microsoft.JSInterop.Infrastructure;
13
13
/// </summary>
14
14
internal readonly struct JSFunctionReference
15
15
{
16
- private static readonly ConcurrentDictionary < Type , MethodInfo > _methodInfoCache = new ( ) ;
17
-
18
- private readonly IJSObjectReference _jsObjectReference ;
19
-
20
16
/// <summary>
21
17
/// Caches previously constructed MethodInfo instances for various delegate types.
22
18
/// </summary>
23
- public static ConcurrentDictionary < Type , MethodInfo > MethodInfoCache => _methodInfoCache ;
19
+ private static readonly ConcurrentDictionary < Type , MethodInfo > _methodInfoCache = new ( ) ;
20
+
21
+ private readonly IJSObjectReference _jsObjectReference ;
24
22
25
23
public JSFunctionReference ( IJSObjectReference jsObjectReference )
26
24
{
@@ -34,84 +32,88 @@ public static T CreateInvocationDelegate<T>(IJSObjectReference jsObjectReference
34
32
{
35
33
Type delegateType = typeof ( T ) ;
36
34
37
- if ( MethodInfoCache . TryGetValue ( delegateType , out var wrapperMethod ) )
35
+ if ( _methodInfoCache . TryGetValue ( delegateType , out var wrapperMethod ) )
38
36
{
39
37
var wrapper = new JSFunctionReference ( jsObjectReference ) ;
40
38
return ( T ) Delegate . CreateDelegate ( delegateType , wrapper , wrapperMethod ) ;
41
39
}
42
40
43
41
if ( ! delegateType . IsGenericType )
44
42
{
45
- throw new ArgumentException ( "The delegate type must be a Func." ) ;
43
+ throw CreateInvalidTypeParameterException ( delegateType ) ;
46
44
}
47
45
48
46
var returnTypeCandidate = delegateType . GenericTypeArguments [ ^ 1 ] ;
49
47
50
48
if ( returnTypeCandidate == typeof ( ValueTask ) )
51
49
{
52
- var methodName = GetVoidMethodName ( delegateType . GetGenericTypeDefinition ( ) ) ;
50
+ var methodName = GetVoidMethodName ( delegateType ) ;
53
51
return CreateVoidDelegate < T > ( delegateType , jsObjectReference , methodName ) ;
54
52
}
55
53
else if ( returnTypeCandidate == typeof ( Task ) )
56
54
{
57
- var methodName = GetVoidTaskMethodName ( delegateType . GetGenericTypeDefinition ( ) ) ;
55
+ var methodName = GetVoidTaskMethodName ( delegateType ) ;
58
56
return CreateVoidDelegate < T > ( delegateType , jsObjectReference , methodName ) ;
59
57
}
60
- else
58
+ else if ( returnTypeCandidate . IsGenericType )
61
59
{
62
60
var returnTypeGenericTypeDefinition = returnTypeCandidate . GetGenericTypeDefinition ( ) ;
63
61
64
62
if ( returnTypeGenericTypeDefinition == typeof ( ValueTask < > ) )
65
63
{
66
- var methodName = GetMethodName ( delegateType . GetGenericTypeDefinition ( ) ) ;
64
+ var methodName = GetMethodName ( delegateType ) ;
67
65
var innerReturnType = returnTypeCandidate . GenericTypeArguments [ 0 ] ;
68
66
return CreateDelegate < T > ( delegateType , innerReturnType , jsObjectReference , methodName ) ;
69
67
}
70
68
71
69
else if ( returnTypeGenericTypeDefinition == typeof ( Task < > ) )
72
70
{
73
- var methodName = GetTaskMethodName ( delegateType . GetGenericTypeDefinition ( ) ) ;
71
+ var methodName = GetTaskMethodName ( delegateType ) ;
74
72
var innerReturnType = returnTypeCandidate . GenericTypeArguments [ 0 ] ;
75
73
return CreateDelegate < T > ( delegateType , innerReturnType , jsObjectReference , methodName ) ;
76
74
}
77
- else
78
- {
79
- throw new ArgumentException ( "The delegate return type must be Task<TResult> or ValueTask<TResult>." ) ;
80
- }
81
75
}
76
+
77
+ throw CreateInvalidTypeParameterException ( delegateType ) ;
82
78
}
83
79
84
80
private static T CreateDelegate < T > ( Type delegateType , Type returnType , IJSObjectReference jsObjectReference , string methodName ) where T : Delegate
85
81
{
86
- var wrapper = new JSFunctionReference ( jsObjectReference ) ;
87
82
var wrapperMethod = typeof ( JSFunctionReference ) . GetMethod ( methodName , BindingFlags . Public | BindingFlags . Instance ) ! ;
88
83
Type [ ] genericArguments = [ .. delegateType . GenericTypeArguments [ ..^ 1 ] , returnType ] ;
89
84
90
85
#pragma warning disable IL2060 // Call to 'System.Reflection.MethodInfo.MakeGenericMethod' can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic method.
91
86
var concreteWrapperMethod = wrapperMethod . MakeGenericMethod ( genericArguments ) ;
92
87
#pragma warning restore IL2060 // Call to 'System.Reflection.MethodInfo.MakeGenericMethod' can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic method.
93
88
94
- MethodInfoCache . TryAdd ( delegateType , concreteWrapperMethod ) ;
89
+ _methodInfoCache . TryAdd ( delegateType , concreteWrapperMethod ) ;
95
90
91
+ var wrapper = new JSFunctionReference ( jsObjectReference ) ;
96
92
return ( T ) Delegate . CreateDelegate ( delegateType , wrapper , concreteWrapperMethod ) ;
97
93
}
98
94
99
95
private static T CreateVoidDelegate < T > ( Type delegateType , IJSObjectReference jsObjectReference , string methodName ) where T : Delegate
100
96
{
101
- var wrapper = new JSFunctionReference ( jsObjectReference ) ;
102
97
var wrapperMethod = typeof ( JSFunctionReference ) . GetMethod ( methodName , BindingFlags . Public | BindingFlags . Instance ) ! ;
103
98
Type [ ] genericArguments = delegateType . GenericTypeArguments [ ..^ 1 ] ;
104
99
105
100
#pragma warning disable IL2060 // Call to 'System.Reflection.MethodInfo.MakeGenericMethod' can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic method.
106
101
var concreteWrapperMethod = wrapperMethod . MakeGenericMethod ( genericArguments ) ;
107
102
#pragma warning restore IL2060 // Call to 'System.Reflection.MethodInfo.MakeGenericMethod' can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic method.
108
103
109
- MethodInfoCache . TryAdd ( delegateType , concreteWrapperMethod ) ;
104
+ _methodInfoCache . TryAdd ( delegateType , concreteWrapperMethod ) ;
110
105
106
+ var wrapper = new JSFunctionReference ( jsObjectReference ) ;
111
107
return ( T ) Delegate . CreateDelegate ( delegateType , wrapper , concreteWrapperMethod ) ;
112
108
}
113
109
114
- private static string GetMethodName ( Type genericDelegateTypeDefiniton ) => genericDelegateTypeDefiniton switch
110
+ private static InvalidOperationException CreateInvalidTypeParameterException ( Type delegateType )
111
+ {
112
+ return new InvalidOperationException (
113
+ $ "The type { delegateType } is not supported as the type parameter of '{ nameof ( JSObjectReferenceExtensions . AsAsyncFunction ) } '. 'T' must be Func with the return type Task<TResult> or ValueTask<TResult>.") ;
114
+ }
115
+
116
+ private static string GetMethodName ( Type delegateType ) => delegateType . GetGenericTypeDefinition ( ) switch
115
117
{
116
118
var gd when gd == typeof ( Func < > ) => nameof ( Invoke0 ) ,
117
119
var gd when gd == typeof ( Func < , > ) => nameof ( Invoke1 ) ,
@@ -120,10 +122,10 @@ private static T CreateVoidDelegate<T>(Type delegateType, IJSObjectReference jsO
120
122
var gd when gd == typeof ( Func < , , , , > ) => nameof ( Invoke4 ) ,
121
123
var gd when gd == typeof ( Func < , , , , , > ) => nameof ( Invoke5 ) ,
122
124
var gd when gd == typeof ( Func < , , , , , , > ) => nameof ( Invoke6 ) ,
123
- _ => throw new NotSupportedException ( $ "The type { genericDelegateTypeDefiniton } is not supported." )
125
+ _ => throw CreateInvalidTypeParameterException ( delegateType )
124
126
} ;
125
127
126
- private static string GetTaskMethodName ( Type genericDelegateTypeDefiniton ) => genericDelegateTypeDefiniton switch
128
+ private static string GetTaskMethodName ( Type delegateType ) => delegateType . GetGenericTypeDefinition ( ) switch
127
129
{
128
130
var gd when gd == typeof ( Func < > ) => nameof ( InvokeTask0 ) ,
129
131
var gd when gd == typeof ( Func < , > ) => nameof ( InvokeTask1 ) ,
@@ -132,10 +134,10 @@ private static T CreateVoidDelegate<T>(Type delegateType, IJSObjectReference jsO
132
134
var gd when gd == typeof ( Func < , , , , > ) => nameof ( InvokeTask4 ) ,
133
135
var gd when gd == typeof ( Func < , , , , , > ) => nameof ( InvokeTask5 ) ,
134
136
var gd when gd == typeof ( Func < , , , , , , > ) => nameof ( InvokeTask6 ) ,
135
- _ => throw new NotSupportedException ( $ "The type { genericDelegateTypeDefiniton } is not supported." )
137
+ _ => throw CreateInvalidTypeParameterException ( delegateType )
136
138
} ;
137
139
138
- private static string GetVoidMethodName ( Type genericDelegateTypeDefiniton ) => genericDelegateTypeDefiniton switch
140
+ private static string GetVoidMethodName ( Type delegateType ) => delegateType . GetGenericTypeDefinition ( ) switch
139
141
{
140
142
var gd when gd == typeof ( Func < > ) => nameof ( InvokeVoid0 ) ,
141
143
var gd when gd == typeof ( Func < , > ) => nameof ( InvokeVoid1 ) ,
@@ -144,10 +146,10 @@ private static T CreateVoidDelegate<T>(Type delegateType, IJSObjectReference jsO
144
146
var gd when gd == typeof ( Func < , , , , > ) => nameof ( InvokeVoid4 ) ,
145
147
var gd when gd == typeof ( Func < , , , , , > ) => nameof ( InvokeVoid5 ) ,
146
148
var gd when gd == typeof ( Func < , , , , , , > ) => nameof ( InvokeVoid6 ) ,
147
- _ => throw new NotSupportedException ( $ "The type { genericDelegateTypeDefiniton } is not supported." )
149
+ _ => throw CreateInvalidTypeParameterException ( delegateType )
148
150
} ;
149
151
150
- private static string GetVoidTaskMethodName ( Type genericDelegateTypeDefiniton ) => genericDelegateTypeDefiniton switch
152
+ private static string GetVoidTaskMethodName ( Type delegateType ) => delegateType . GetGenericTypeDefinition ( ) switch
151
153
{
152
154
var gd when gd == typeof ( Func < > ) => nameof ( InvokeVoidTask0 ) ,
153
155
var gd when gd == typeof ( Func < , > ) => nameof ( InvokeVoidTask1 ) ,
@@ -156,7 +158,7 @@ private static T CreateVoidDelegate<T>(Type delegateType, IJSObjectReference jsO
156
158
var gd when gd == typeof ( Func < , , , , > ) => nameof ( InvokeVoidTask4 ) ,
157
159
var gd when gd == typeof ( Func < , , , , , > ) => nameof ( InvokeVoidTask5 ) ,
158
160
var gd when gd == typeof ( Func < , , , , , , > ) => nameof ( InvokeVoidTask6 ) ,
159
- _ => throw new NotSupportedException ( $ "The type { genericDelegateTypeDefiniton } is not supported." )
161
+ _ => throw CreateInvalidTypeParameterException ( delegateType )
160
162
} ;
161
163
162
164
// Variants returning ValueTask<T> using InvokeAsync
0 commit comments