@@ -15,54 +15,56 @@ public static class CachedExpressionCompiler
1515// relying on cache lookups and other techniques to save time if appropriate.
1616// If the provided expression is particularly obscure and the system doesn't know
1717// how to handle it, we'll just compile the expression as normal.
18- public static Func < TModel , TValue > Process < TModel , TValue > (
19- [ NotNull ] Expression < Func < TModel , TValue > > lambdaExpression )
18+ public static Func < TModel , TResult > Process < TModel , TResult > (
19+ [ NotNull ] Expression < Func < TModel , TResult > > expression )
2020{
21- return Compiler < TModel , TValue > . Compile ( lambdaExpression ) ;
21+ return Compiler < TModel , TResult > . Compile ( expression ) ;
2222}
2323
24- private static class Compiler < TIn , TOut >
24+ private static class Compiler < TModel , TResult >
2525{
26- private static Func < TIn , TOut > _identityFunc ;
26+ private static Func < TModel , TResult > _identityFunc ;
2727
28- private static readonly ConcurrentDictionary < MemberInfo , Func < TIn , TOut > > _simpleMemberAccessDict =
29- new ConcurrentDictionary < MemberInfo , Func < TIn , TOut > > ( ) ;
28+ private static readonly ConcurrentDictionary < MemberInfo , Func < TModel , TResult > > _simpleMemberAccessDict =
29+ new ConcurrentDictionary < MemberInfo , Func < TModel , TResult > > ( ) ;
3030
31- private static readonly ConcurrentDictionary < MemberInfo , Func < object , TOut > > _constMemberAccessDict =
32- new ConcurrentDictionary < MemberInfo , Func < object , TOut > > ( ) ;
31+ private static readonly ConcurrentDictionary < MemberInfo , Func < object , TResult > > _constMemberAccessDict =
32+ new ConcurrentDictionary < MemberInfo , Func < object , TResult > > ( ) ;
3333
34- public static Func < TIn , TOut > Compile ( [ NotNull ] Expression < Func < TIn , TOut > > expr )
34+ public static Func < TModel , TResult > Compile ( [ NotNull ] Expression < Func < TModel , TResult > > expression )
3535{
36- return CompileFromIdentityFunc ( expr )
37- ?? CompileFromConstLookup ( expr )
38- ?? CompileFromMemberAccess ( expr )
39- ?? CompileSlow ( expr ) ;
36+ return CompileFromIdentityFunc ( expression )
37+ ?? CompileFromConstLookup ( expression )
38+ ?? CompileFromMemberAccess ( expression )
39+ ?? CompileSlow ( expression ) ;
4040}
4141
42- private static Func < TIn , TOut > CompileFromConstLookup ( [ NotNull ] Expression < Func < TIn , TOut > > expr )
42+ private static Func < TModel , TResult > CompileFromConstLookup (
43+ [ NotNull ] Expression < Func < TModel , TResult > > expression )
4344{
44- var constExpr = expr . Body as ConstantExpression ;
45- if ( constExpr != null )
45+ var constantExpression = expression . Body as ConstantExpression ;
46+ if ( constantExpression != null )
4647{
4748// model => {const}
4849
49- var constantValue = ( TOut ) constExpr . Value ;
50+ var constantValue = ( TResult ) constantExpression . Value ;
5051return _=> constantValue ;
5152}
5253
5354return null ;
5455}
5556
56- private static Func < TIn , TOut > CompileFromIdentityFunc ( [ NotNull ] Expression < Func < TIn , TOut > > expr )
57+ private static Func < TModel , TResult > CompileFromIdentityFunc (
58+ [ NotNull ] Expression < Func < TModel , TResult > > expression )
5759{
58- if ( expr . Body == expr . Parameters [ 0 ] )
60+ if ( expression . Body == expression . Parameters [ 0 ] )
5961{
6062// model => model
6163
6264// Don't need to lock, as all identity funcs are identical.
6365if ( _identityFunc == null )
6466{
65- _identityFunc = expr . Compile ( ) ;
67+ _identityFunc = expression . Compile ( ) ;
6668}
6769
6870return _identityFunc ;
@@ -71,50 +73,52 @@ private static Func<TIn, TOut> CompileFromIdentityFunc([NotNull] Expression<Func
7173return null ;
7274}
7375
74- private static Func < TIn , TOut > CompileFromMemberAccess ( [ NotNull ] Expression < Func < TIn , TOut > > expr )
76+ private static Func < TModel , TResult > CompileFromMemberAccess (
77+ [ NotNull ] Expression < Func < TModel , TResult > > expression )
7578{
7679// Performance tests show that on the x64 platform, special-casing static member and
7780// captured local variable accesses is faster than letting the fingerprinting system
7881// handle them. On the x86 platform, the fingerprinting system is faster, but only
7982// by around one microsecond, so it's not worth it to complicate the logic here with
8083// an architecture check.
8184
82- var memberExpr = expr . Body as MemberExpression ;
83- if ( memberExpr != null )
85+ var memberExpression = expression . Body as MemberExpression ;
86+ if ( memberExpression != null )
8487{
85- if ( memberExpr . Expression == expr . Parameters [ 0 ] || memberExpr . Expression == null )
88+ if ( memberExpression . Expression == expression . Parameters [ 0 ] || memberExpression . Expression == null )
8689{
8790// model => model.Member or model => StaticMember
88- return _simpleMemberAccessDict . GetOrAdd ( memberExpr . Member , _=> expr . Compile ( ) ) ;
91+ return _simpleMemberAccessDict . GetOrAdd ( memberExpression . Member , _=> expression . Compile ( ) ) ;
8992}
9093
91- var constExpr = memberExpr . Expression as ConstantExpression ;
92- if ( constExpr != null )
94+ var constantExpression = memberExpression . Expression as ConstantExpression ;
95+ if ( constantExpression != null )
9396{
9497// model => {const}.Member (captured local variable)
95- var del = _constMemberAccessDict . GetOrAdd ( memberExpr . Member , _=>
98+ var compiledExpression = _constMemberAccessDict . GetOrAdd ( memberExpression . Member , _=>
9699{
97100// rewrite as capturedLocal => ((TDeclaringType)capturedLocal).Member
98- var constParamExpr = Expression . Parameter ( typeof ( object ) , "capturedLocal" ) ;
99- var constCastExpr = Expression . Convert ( constParamExpr , memberExpr . Member . DeclaringType ) ;
100- var newMemberAccessExpr = memberExpr . Update ( constCastExpr ) ;
101- var newLambdaExpr =
102- Expression . Lambda < Func < object , TOut > > ( newMemberAccessExpr , constParamExpr ) ;
103- return newLambdaExpr . Compile ( ) ;
101+ var parameterExpression = Expression . Parameter ( typeof ( object ) , "capturedLocal" ) ;
102+ var castExpression =
103+ Expression . Convert ( parameterExpression , memberExpression . Member . DeclaringType ) ;
104+ var newMemberExpression = memberExpression . Update ( castExpression ) ;
105+ var newExpression =
106+ Expression . Lambda < Func < object , TResult > > ( newMemberExpression , parameterExpression ) ;
107+ return newExpression . Compile ( ) ;
104108} ) ;
105109
106- var capturedLocal = constExpr . Value ;
107- return _=> del ( capturedLocal ) ;
110+ var capturedLocal = constantExpression . Value ;
111+ return _=> compiledExpression ( capturedLocal ) ;
108112}
109113}
110114
111115return null ;
112116}
113117
114- private static Func < TIn , TOut > CompileSlow ( [ NotNull ] Expression < Func < TIn , TOut > > expr )
118+ private static Func < TModel , TResult > CompileSlow ( [ NotNull ] Expression < Func < TModel , TResult > > expression )
115119{
116120// fallback compilation system - just compile the expression directly
117- return expr . Compile ( ) ;
121+ return expression . Compile ( ) ;
118122}
119123}
120124}