1
1
using System ;
2
+ using System . Diagnostics ;
2
3
using System . Diagnostics . CodeAnalysis ;
3
4
using System . Reflection ;
4
5
using System . Runtime . Serialization ;
@@ -17,8 +18,9 @@ internal struct MaybeMethodBase<T> : ISerializable where T: MethodBase
17
18
const string SerializationType = "t" ;
18
19
// Fhe parameters of the MethodBase
19
20
const string SerializationParameters = "p" ;
20
- const string SerializationIsCtor = "c" ;
21
21
const string SerializationMethodName = "n" ;
22
+ const string SerializationGenericParamCount = "G" ;
23
+ const string SerializationFlags = "V" ;
22
24
23
25
public static implicit operator MaybeMethodBase < T > ( T ? ob ) => new ( ob ) ;
24
26
@@ -62,6 +64,7 @@ public MaybeMethodBase(T? mi)
62
64
{
63
65
info = mi ;
64
66
name = mi ? . ToString ( ) ;
67
+ Debug . Assert ( name != null || info == null ) ;
65
68
deserializationException = null ;
66
69
}
67
70
@@ -82,75 +85,60 @@ internal MaybeMethodBase(SerializationInfo serializationInfo, StreamingContext c
82
85
{
83
86
throw new SerializationException ( $ "The underlying type{ typeName } can't be found") ;
84
87
}
88
+
89
+ var flags = ( MaybeMethodFlags ) serializationInfo . GetInt32 ( SerializationFlags ) ;
90
+ int genericCount = serializationInfo . GetInt32 ( SerializationGenericParamCount ) ;
91
+
85
92
// Get the method's parameters types
86
93
var field_name = serializationInfo . GetString ( SerializationMethodName ) ;
87
94
var param = ( ParameterHelper [ ] ) serializationInfo . GetValue ( SerializationParameters , typeof ( ParameterHelper [ ] ) ) ;
88
- Type [ ] types = new Type [ param . Length ] ;
89
- bool hasRefType = false ;
90
- for ( int i = 0 ; i < param . Length ; i ++ )
91
- {
92
- var paramTypeName = param [ i ] . TypeName ;
93
- types [ i ] = Type . GetType ( paramTypeName ) ;
94
- if ( types [ i ] == null )
95
- {
96
- throw new SerializationException ( $ "The parameter of type{ paramTypeName } can't be found") ;
97
- }
98
- else if ( types [ i ] . IsByRef )
99
- {
100
- hasRefType = true ;
101
- }
102
- }
103
95
104
- MethodBase ? mb = null ;
105
- if ( serializationInfo . GetBoolean ( SerializationIsCtor ) )
106
- {
107
- // We never want the static constructor.
108
- mb = tp . GetConstructor ( ClassManager . BindingFlags & ( ~ BindingFlags . Static ) , binder : null , types : types , modifiers : null ) ;
109
- }
110
- else
111
- {
112
- mb = tp . GetMethod ( field_name , ClassManager . BindingFlags , binder : null , types : types , modifiers : null ) ;
113
- }
114
-
115
- if ( mb != null && hasRefType )
116
- {
117
- mb = CheckRefTypes ( mb , param ) ;
118
- }
119
-
120
- // Do like in ClassManager.GetClassInfo
121
- if ( mb != null && ClassManager . ShouldBindMethod ( mb ) )
122
- {
123
- info = mb ;
124
- }
96
+ info = ScanForMethod ( tp , field_name , genericCount , flags , param ) ;
125
97
}
126
98
catch ( Exception e )
127
99
{
128
100
deserializationException = e ;
129
101
}
130
102
}
131
103
132
- MethodBase ? CheckRefTypes ( MethodBase mb , ParameterHelper [ ] ph )
104
+ static MethodBase ScanForMethod ( Type declaringType , string name , int genericCount , MaybeMethodFlags flags , ParameterHelper [ ] parameters )
133
105
{
134
- // One more step: Changing:
135
- // void MyFn (ref int a)
136
- // to:
137
- // void MyFn (out int a)
138
- // will still find the function correctly as, `in`, `out` and `ref`
139
- // are all represented as a reference type. Query the method we got
140
- // and validate the parameters
141
- if ( ph . Length != 0 )
142
- {
143
- foreach ( var item in Enumerable . Zip ( ph , mb . GetParameters ( ) , ( orig , current ) => new { orig , current } ) )
144
- {
145
- if ( ! item . current . Equals ( item . orig ) )
146
- {
147
- // False positive
148
- return null ;
149
- }
150
- }
151
- }
106
+ var bindingFlags = ClassManager . BindingFlags ;
107
+ if ( flags . HasFlag ( MaybeMethodFlags . Constructor ) ) bindingFlags &= ~ BindingFlags . Static ;
152
108
153
- return mb ;
109
+ var alternatives = declaringType . GetMember ( name ,
110
+ flags . HasFlag ( MaybeMethodFlags . Constructor )
111
+ ? MemberTypes . Constructor
112
+ : MemberTypes . Method ,
113
+ bindingFlags ) ;
114
+
115
+ if ( alternatives . Length == 0 )
116
+ throw new MissingMethodException ( $ "{ declaringType } .{ name } ") ;
117
+
118
+ var visibility = flags & MaybeMethodFlags . Visibility ;
119
+
120
+ var result = alternatives . Cast < MethodBase > ( ) . FirstOrDefault ( m
121
+ => MatchesGenericCount ( m , genericCount ) && MatchesSignature ( m , parameters )
122
+ && ( Visibility ( m ) == visibility || ClassManager . ShouldBindMethod ( m ) ) ) ;
123
+
124
+ if ( result is null )
125
+ throw new MissingMethodException ( $ "Matching overload not found for{ declaringType } .{ name } ") ;
126
+
127
+ return result ;
128
+ }
129
+
130
+ static bool MatchesGenericCount ( MethodBase method , int genericCount )
131
+ => method . ContainsGenericParameters
132
+ ? method . GetGenericArguments ( ) . Length == genericCount
133
+ : genericCount == 0 ;
134
+
135
+ static bool MatchesSignature ( MethodBase method , ParameterHelper [ ] parameters )
136
+ {
137
+ var curr = method . GetParameters ( ) ;
138
+ if ( curr . Length != parameters . Length ) return false ;
139
+ for ( int i = 0 ; i < curr . Length ; i ++ )
140
+ if ( ! parameters [ i ] . Matches ( curr [ i ] ) ) return false ;
141
+ return true ;
154
142
}
155
143
156
144
public void GetObjectData ( SerializationInfo serializationInfo , StreamingContext context )
@@ -159,11 +147,39 @@ public void GetObjectData(SerializationInfo serializationInfo, StreamingContext
159
147
if ( Valid )
160
148
{
161
149
serializationInfo . AddValue ( SerializationMethodName , info . Name ) ;
162
- serializationInfo . AddValue ( SerializationType , info . ReflectedType . AssemblyQualifiedName ) ;
150
+ serializationInfo . AddValue ( SerializationGenericParamCount ,
151
+ info . ContainsGenericParameters ? info . GetGenericArguments ( ) . Length : 0 ) ;
152
+ serializationInfo . AddValue ( SerializationFlags , ( int ) Flags ( info ) ) ;
153
+ string ? typeName = info . ReflectedType . AssemblyQualifiedName ;
154
+ Debug . Assert ( typeName != null ) ;
155
+ serializationInfo . AddValue ( SerializationType , typeName ) ;
163
156
ParameterHelper [ ] parameters = ( from p in info . GetParameters ( ) select new ParameterHelper ( p ) ) . ToArray ( ) ;
164
157
serializationInfo . AddValue ( SerializationParameters , parameters , typeof ( ParameterHelper [ ] ) ) ;
165
- serializationInfo . AddValue ( SerializationIsCtor , info . IsConstructor ) ;
166
158
}
167
159
}
160
+
161
+ static MaybeMethodFlags Flags ( MethodBase method )
162
+ {
163
+ var flags = MaybeMethodFlags . Default ;
164
+ if ( method . IsConstructor ) flags |= MaybeMethodFlags . Constructor ;
165
+ if ( method . IsStatic ) flags |= MaybeMethodFlags . Static ;
166
+ if ( method . IsPublic ) flags |= MaybeMethodFlags . Public ;
167
+ return flags ;
168
+ }
169
+
170
+ static MaybeMethodFlags Visibility ( MethodBase method )
171
+ => Flags ( method ) & MaybeMethodFlags . Visibility ;
172
+ }
173
+
174
+ [ Flags ]
175
+ internal enum MaybeMethodFlags
176
+ {
177
+ Default = 0 ,
178
+ Constructor = 1 ,
179
+ Static = 2 ,
180
+
181
+ // TODO: other kinds of visibility
182
+ Public = 32 ,
183
+ Visibility = Public ,
168
184
}
169
185
}