11using System . Collections . Generic ;
22using System . Reflection ;
33
4+ using BizHawk . Common ;
45using BizHawk . Common . ReflectionExtensions ;
56
67namespace BizHawk . Emulation . Common
@@ -14,9 +15,9 @@ private readonly struct ServicePropInfo
1415 {
1516 public readonly Type PropType ;
1617
17- public readonly MethodInfo Setter ;
18+ public readonly MethodInfo ? Setter ;
1819
19- public ServicePropInfo ( Type propType , MethodInfo setter )
20+ public ServicePropInfo ( Type propType , MethodInfo ? setter )
2021 {
2122 PropType = propType ;
2223 Setter = setter ;
@@ -29,18 +30,26 @@ private static (List<ServicePropInfo> Req, List<ServicePropInfo> Opt) GetService
2930 this Type @class ,
3031 bool mayCache )
3132 {
33+ const string ERR_FMT_STR_GETONLY_PROP = "prop `[{0}] {1}.{2}` is get-only" ;
3234 if ( _cache . TryGetValue ( @class , out var pair ) ) return pair ;
3335 pair = ( new ( ) , new ( ) ) ;
3436 foreach ( var pi in @class . GetProperties ( ReflectionExtensions . DI_TARGET_PROPS ) )
3537 {
36- //TODO enumerate attrs only once
37- if ( pi . GetCustomAttributes ( typeof ( RequiredServiceAttribute ) , inherit : false ) . Length is not 0 )
38+ foreach ( var attr in pi . GetCustomAttributes ( ) )
3839 {
39- pair . Req . Add ( new ( pi . PropertyType , pi . GetSetMethod ( nonPublic : true ) ) ) ;
40- }
41- else if ( pi . GetCustomAttributes ( typeof ( OptionalServiceAttribute ) , inherit : false ) . Length is not 0 )
42- {
43- pair . Opt . Add ( new ( pi . PropertyType , pi . GetSetMethod ( nonPublic : true ) ) ) ;
40+ if ( attr is RequiredServiceAttribute )
41+ {
42+ var setter = pi . GetSetMethod ( nonPublic : true ) ;
43+ if ( setter is null ) Util . DebugWriteLine ( ERR_FMT_STR_GETONLY_PROP , "RequiredService" , @class . Name , pi . Name ) ;
44+ pair . Req . Add ( new ( pi . PropertyType , setter ) ) ; // pass through anyway, and `UpdateServices` will see it and `return false;`
45+ break ;
46+ }
47+ else if ( attr is OptionalServiceAttribute )
48+ {
49+ if ( pi . GetSetMethod ( nonPublic : true ) is MethodInfo setter ) pair . Req . Add ( new ( pi . PropertyType , setter ) ) ;
50+ else Util . DebugWriteLine ( ERR_FMT_STR_GETONLY_PROP , "OptionalService" , @class . Name , pi . Name ) ;
51+ break ;
52+ }
4453 }
4554 }
4655 if ( mayCache ) _cache [ @class ] = pair ;
@@ -69,12 +78,13 @@ public static bool UpdateServices(IEmulatorServiceProvider source, object target
6978 {
7079 return false ;
7180 }
81+ if ( info . Setter is null ) return false ;
7282 info . Setter . Invoke ( target , tmp ) ;
7383 }
7484 foreach ( var info in opt )
7585 {
7686 tmp [ 0 ] = source . GetService ( info . PropType ) ;
77- info . Setter . Invoke ( target , tmp ) ;
87+ info . Setter ! . Invoke ( target , tmp ) ;
7888 }
7989
8090 return true ;
0 commit comments