@@ -32,6 +32,18 @@ public override object Cast(object obj, Type castTo)
32
32
return Il2CppCast ( obj , castTo ) ;
33
33
}
34
34
35
+ public override T TryCast < T > ( object obj )
36
+ {
37
+ try
38
+ {
39
+ return ( T ) Il2CppCast ( obj , typeof ( T ) ) ;
40
+ }
41
+ catch
42
+ {
43
+ return default ;
44
+ }
45
+ }
46
+
35
47
public override string ProcessTypeNameInString ( Type type , string theString , ref string typeName )
36
48
{
37
49
if ( ! Il2CppTypeNotNull ( type ) )
@@ -367,6 +379,124 @@ public static object Unbox(object obj, Type type)
367
379
368
380
return s_unboxMethods [ name ] . Invoke ( obj , new object [ 0 ] ) ;
369
381
}
382
+
383
+ public override string UnboxString ( object value )
384
+ {
385
+ string s = null ;
386
+ // strings boxed as Il2CppSystem.Objects can behave weirdly.
387
+ // GetActualType will find they are a string, but if its boxed
388
+ // then we need to unbox it like this...
389
+ if ( ! ( value is string ) && value is Il2CppSystem . Object cppobj )
390
+ s = cppobj . ToString ( ) ;
391
+
392
+ return s ;
393
+ }
394
+
395
+ internal static readonly Dictionary < Type , MethodInfo > s_getEnumeratorMethods = new Dictionary < Type , MethodInfo > ( ) ;
396
+
397
+ internal static readonly Dictionary < Type , EnumeratorInfo > s_enumeratorInfos = new Dictionary < Type , EnumeratorInfo > ( ) ;
398
+
399
+ internal class EnumeratorInfo
400
+ {
401
+ internal MethodInfo moveNext ;
402
+ internal PropertyInfo current ;
403
+ }
404
+
405
+ public override IEnumerable EnumerateEnumerable ( object value )
406
+ {
407
+ if ( value == null )
408
+ return null ;
409
+
410
+ var cppEnumerable = ( value as Il2CppSystem . Object ) ? . TryCast < Il2CppSystem . Collections . IEnumerable > ( ) ;
411
+ if ( cppEnumerable != null )
412
+ {
413
+ var type = value . GetType ( ) ;
414
+ if ( ! s_getEnumeratorMethods . ContainsKey ( type ) )
415
+ s_getEnumeratorMethods . Add ( type , type . GetMethod ( "GetEnumerator" ) ) ;
416
+
417
+ var enumerator = s_getEnumeratorMethods [ type ] . Invoke ( value , null ) ;
418
+ var enumeratorType = enumerator . GetType ( ) ;
419
+
420
+ if ( ! s_enumeratorInfos . ContainsKey ( enumeratorType ) )
421
+ {
422
+ s_enumeratorInfos . Add ( enumeratorType , new EnumeratorInfo
423
+ {
424
+ current = enumeratorType . GetProperty ( "Current" ) ,
425
+ moveNext = enumeratorType . GetMethod ( "MoveNext" ) ,
426
+ } ) ;
427
+ }
428
+ var info = s_enumeratorInfos [ enumeratorType ] ;
429
+
430
+ // iterate
431
+ var list = new List < object > ( ) ;
432
+ while ( ( bool ) info . moveNext . Invoke ( enumerator , null ) )
433
+ list . Add ( info . current . GetValue ( enumerator ) ) ;
434
+
435
+ return list ;
436
+ }
437
+
438
+ return null ;
439
+ }
440
+
441
+ public override IDictionary EnumerateDictionary ( object value , Type typeOfKeys , Type typeOfValues )
442
+ {
443
+ var valueType = ReflectionUtility . GetActualType ( value ) ;
444
+
445
+ var keyList = new List < object > ( ) ;
446
+ var valueList = new List < object > ( ) ;
447
+
448
+ var hashtable = value . Cast ( typeof ( Il2CppSystem . Collections . Hashtable ) ) as Il2CppSystem . Collections . Hashtable ;
449
+
450
+ if ( hashtable != null )
451
+ {
452
+ EnumerateCppHashtable ( hashtable , keyList , valueList ) ;
453
+ }
454
+ else
455
+ {
456
+ var keys = valueType . GetProperty ( "Keys" ) . GetValue ( value , null ) ;
457
+ var values = valueType . GetProperty ( "Values" ) . GetValue ( value , null ) ;
458
+
459
+ EnumerateCppIDictionary ( keys , keyList ) ;
460
+ EnumerateCppIDictionary ( values , valueList ) ;
461
+ }
462
+
463
+ var dict = Activator . CreateInstance ( typeof ( Dictionary < , > )
464
+ . MakeGenericType ( typeOfKeys , typeOfValues ) )
465
+ as IDictionary ;
466
+
467
+ for ( int i = 0 ; i < keyList . Count ; i ++ )
468
+ dict . Add ( keyList [ i ] , valueList [ i ] ) ;
469
+
470
+ return dict ;
471
+ }
472
+
473
+ private void EnumerateCppIDictionary ( object collection , List < object > list )
474
+ {
475
+ // invoke GetEnumerator
476
+ var enumerator = collection . GetType ( ) . GetMethod ( "GetEnumerator" ) . Invoke ( collection , null ) ;
477
+ // get the type of it
478
+ var enumeratorType = enumerator . GetType ( ) ;
479
+ // reflect MoveNext and Current
480
+ var moveNext = enumeratorType . GetMethod ( "MoveNext" ) ;
481
+ var current = enumeratorType . GetProperty ( "Current" ) ;
482
+ // iterate
483
+ while ( ( bool ) moveNext . Invoke ( enumerator , null ) )
484
+ {
485
+ list . Add ( current . GetValue ( enumerator , null ) ) ;
486
+ }
487
+ }
488
+
489
+ private void EnumerateCppHashtable ( Il2CppSystem . Collections . Hashtable hashtable , List < object > keys , List < object > values )
490
+ {
491
+ for ( int i = 0 ; i < hashtable . buckets . Count ; i ++ )
492
+ {
493
+ var bucket = hashtable . buckets [ i ] ;
494
+ if ( bucket == null || bucket . key == null )
495
+ continue ;
496
+ keys . Add ( bucket . key ) ;
497
+ values . Add ( bucket . val ) ;
498
+ }
499
+ }
370
500
}
371
501
}
372
502
0 commit comments