11using System ;
2+ using System . Diagnostics ;
23using System . Diagnostics . CodeAnalysis ;
34using System . Reflection ;
45using System . Runtime . Serialization ;
@@ -17,8 +18,9 @@ internal struct MaybeMethodBase<T> : ISerializable where T: MethodBase
1718 const string SerializationType = "t" ;
1819 // Fhe parameters of the MethodBase
1920 const string SerializationParameters = "p" ;
20- const string SerializationIsCtor = "c" ;
2121 const string SerializationMethodName = "n" ;
22+ const string SerializationGenericParamCount = "G" ;
23+ const string SerializationFlags = "V" ;
2224
2325 public static implicit operator MaybeMethodBase < T > ( T ? ob ) => new ( ob ) ;
2426
@@ -62,6 +64,7 @@ public MaybeMethodBase(T? mi)
6264 {
6365 info = mi ;
6466 name = mi ? . ToString ( ) ;
67+ Debug . Assert ( name != null || info == null ) ;
6568 deserializationException = null ;
6669 }
6770
@@ -82,75 +85,60 @@ internal MaybeMethodBase(SerializationInfo serializationInfo, StreamingContext c
8285 {
8386 throw new SerializationException ( $ "The underlying type { typeName } can't be found") ;
8487 }
88+
89+ var flags = ( MaybeMethodFlags ) serializationInfo . GetInt32 ( SerializationFlags ) ;
90+ int genericCount = serializationInfo . GetInt32 ( SerializationGenericParamCount ) ;
91+
8592 // Get the method's parameters types
8693 var field_name = serializationInfo . GetString ( SerializationMethodName ) ;
8794 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- }
10395
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 ) ;
12597 }
12698 catch ( Exception e )
12799 {
128100 deserializationException = e ;
129101 }
130102 }
131103
132- MethodBase ? CheckRefTypes ( MethodBase mb , ParameterHelper [ ] ph )
104+ static MethodBase ScanForMethod ( Type declaringType , string name , int genericCount , MaybeMethodFlags flags , ParameterHelper [ ] parameters )
133105 {
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 ;
152108
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 ;
154142 }
155143
156144 public void GetObjectData ( SerializationInfo serializationInfo , StreamingContext context )
@@ -159,11 +147,39 @@ public void GetObjectData(SerializationInfo serializationInfo, StreamingContext
159147 if ( Valid )
160148 {
161149 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 ) ;
163156 ParameterHelper [ ] parameters = ( from p in info . GetParameters ( ) select new ParameterHelper ( p ) ) . ToArray ( ) ;
164157 serializationInfo . AddValue ( SerializationParameters , parameters , typeof ( ParameterHelper [ ] ) ) ;
165- serializationInfo . AddValue ( SerializationIsCtor , info . IsConstructor ) ;
166158 }
167159 }
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 ,
168184 }
169185}
0 commit comments