11using System . Reflection ;
22using System . Reflection . Emit ;
3+ using Fluid . Values ;
34
45namespace Fluid . Accessors
56{
67 public sealed class PropertyInfoAccessor : IMemberAccessor
78 {
8- private readonly IInvoker _invoker ;
9+ private readonly Invoker _invoker ;
910
1011 public PropertyInfoAccessor ( PropertyInfo propertyInfo )
1112 {
1213 Delegate d ;
1314
14- if ( ! propertyInfo . DeclaringType . IsValueType )
15+ if ( ! propertyInfo . DeclaringType ? . IsValueType == true )
1516 {
1617 var delegateType = typeof ( Func < , > ) . MakeGenericType ( propertyInfo . DeclaringType , propertyInfo . PropertyType ) ;
1718 d = propertyInfo . GetGetMethod ( ) . CreateDelegate ( delegateType ) ;
@@ -21,7 +22,7 @@ public PropertyInfoAccessor(PropertyInfo propertyInfo)
2122 // We can't create an open delegate on a struct (dotnet limitation?), so instead create custom delegates
2223 // https://sharplab.io/#v2:EYLgtghglgdgNAFxAJwK7wCYgNQB8ACATAAwCwAUEQIwX7EAE+VAdACLIQDusA5gNwUKANwjJ6ABwCSMAGYB7egF56CAJ7iApnJkAKAApzYCAJTMA4hoR7kczcjU6ARAA1HxgeRFiMhJROny5pYWCACylgAWchg6pgDCyBoQCBqsGgA2GjzJGjpqmto6+ACsADwGRnD0RgB8xu4UQA==
2324 // Instead we generate IL to access the backing field directly
24-
25+
2526 d = GetGetter ( propertyInfo . DeclaringType , propertyInfo . Name ) ;
2627 }
2728
@@ -30,58 +31,76 @@ public PropertyInfoAccessor(PropertyInfo propertyInfo)
3031 _invoker = null ;
3132 }
3233
33- var invokerType = typeof ( Invoker < , > ) . MakeGenericType ( propertyInfo . DeclaringType , propertyInfo . PropertyType ) ;
34- _invoker = Activator . CreateInstance ( invokerType , [ d ] ) as IInvoker ;
35- }
34+ Type invokerType ;
35+ if ( propertyInfo . PropertyType == typeof ( bool ) )
36+ {
37+ invokerType = typeof ( BooleanInvoker < > ) . MakeGenericType ( propertyInfo . DeclaringType ) ;
38+ }
39+ else if ( propertyInfo . PropertyType == typeof ( int ) )
40+ {
41+ invokerType = typeof ( Int32Invoker < > ) . MakeGenericType ( propertyInfo . DeclaringType ) ;
42+ }
43+ else
44+ {
45+ invokerType = typeof ( Invoker < , > ) . MakeGenericType ( propertyInfo . DeclaringType , propertyInfo . PropertyType ) ;
46+ }
3647
37- public object Get ( object obj , string name , TemplateContext ctx )
38- {
39- return _invoker ? . Invoke ( obj ) ;
48+ _invoker = ( Invoker ) Activator . CreateInstance ( invokerType , [ d ] ) ;
4049 }
4150
51+ public object Get ( object obj , string name , TemplateContext ctx ) => _invoker . Invoke ( obj ) ;
52+
4253 private static Delegate GetGetter ( Type declaringType , string fieldName )
4354 {
44- string [ ] names = [ fieldName . ToLowerInvariant ( ) , $ "<{ fieldName } >k__BackingField", "_" + fieldName . ToLowerInvariant ( ) ] ;
45-
46- var field = names
47- . Select ( n => declaringType . GetField ( n , BindingFlags . Instance | BindingFlags . NonPublic ) )
48- . FirstOrDefault ( x => x != null ) ;
55+ string [ ] names = [ fieldName . ToLowerInvariant ( ) , $ "<{ fieldName } >k__BackingField", $ "_{ fieldName . ToLowerInvariant ( ) } "] ;
4956
50- if ( field == null )
57+ foreach ( var n in names )
5158 {
52- return null ;
53- }
59+ var field = declaringType . GetField ( n , BindingFlags . Instance | BindingFlags . NonPublic ) ;
60+ if ( field == null )
61+ {
62+ continue ;
63+ }
5464
55- var parameterTypes = new [ ] { typeof ( object ) , declaringType } ;
65+ var parameterTypes = new [ ] { typeof ( object ) , declaringType } ;
5666
57- var method = new DynamicMethod ( fieldName + "Get" , field . FieldType , parameterTypes , typeof ( PropertyInfoAccessor ) . Module , true ) ;
67+ var method = new DynamicMethod ( fieldName + "Get" , field . FieldType , parameterTypes , typeof ( PropertyInfoAccessor ) . Module , true ) ;
5868
59- var emitter = method . GetILGenerator ( ) ;
60- emitter . Emit ( OpCodes . Ldarg_1 ) ;
61- emitter . Emit ( OpCodes . Ldfld , field ) ;
62- emitter . Emit ( OpCodes . Ret ) ;
69+ var emitter = method . GetILGenerator ( ) ;
70+ emitter . Emit ( OpCodes . Ldarg_1 ) ;
71+ emitter . Emit ( OpCodes . Ldfld , field ) ;
72+ emitter . Emit ( OpCodes . Ret ) ;
6373
64- return method . CreateDelegate ( typeof ( Func < , > ) . MakeGenericType ( declaringType , field . FieldType ) ) ;
74+ return method . CreateDelegate ( typeof ( Func < , > ) . MakeGenericType ( declaringType , field . FieldType ) ) ;
75+ }
76+
77+ return null ;
6578 }
6679
67- private interface IInvoker
80+ private abstract class Invoker
6881 {
69- object Invoke ( object target ) ;
82+ public abstract object Invoke ( object target ) ;
7083 }
7184
72- private sealed class Invoker < T , TResult > : IInvoker
85+ private sealed class Invoker < T , TResult > ( Delegate d ) : Invoker
7386 {
74- private readonly Func < T , TResult > _d ;
87+ private readonly Func < T , TResult > _d = ( Func < T , TResult > ) d ;
7588
76- public Invoker ( Delegate d )
77- {
78- _d = ( Func < T , TResult > ) d ;
79- }
89+ public override object Invoke ( object target ) => _d ( ( T ) target ) ;
90+ }
8091
81- public object Invoke ( object target )
82- {
83- return _d ( ( T ) target ) ;
84- }
92+ private sealed class BooleanInvoker < T > ( Delegate d ) : Invoker
93+ {
94+ private readonly Func < T , bool > _d = ( Func < T , bool > ) d ;
95+
96+ public override object Invoke ( object target ) => _d ( ( T ) target ) ? BooleanValue . True : BooleanValue . False ;
97+ }
98+
99+ private sealed class Int32Invoker < T > ( Delegate d ) : Invoker
100+ {
101+ private readonly Func < T , int > _d = ( Func < T , int > ) d ;
102+
103+ public override object Invoke ( object target ) => NumberValue . Create ( _d ( ( T ) target ) ) ;
85104 }
86105 }
87106}
0 commit comments