コード例 #1
0
        /// <summary>
        ///     Returns a new delegate that safely gets the result of the specified expression
        ///     fragments.
        /// </summary>
        /// <typeparam name="TSource">The instance type.</typeparam>
        /// <typeparam name="TResult">The result type.</typeparam>
        /// <param name="expressionFragments">The expression fragments, which will be processed in the order as specified.</param>
        /// <returns>The result or the default value of the result type, if one or more of the referenced members in the expression are <c>null</c>.</returns>
        private static Func <TSource, TResult> CreateSafeGetDelegate <TSource, TResult>(IList <MemberExpression> expressionFragments)
        {
            List <Expression> targetFragments    = new List <Expression>();
            MemberExpression  lastSourceFragment = expressionFragments.Last();

            ParameterExpression instanceParameter = Expression.Variable(typeof(object), "instance");
            ParameterExpression resultVariable    = Expression.Variable(typeof(TResult), "result");

            LabelTarget useDefaultLabel = Expression.Label("useDefault");
            LabelTarget returnLabel     = Expression.Label("return");

            foreach (MemberExpression sourceFragment in expressionFragments)
            {
                MemberInfo memberInfo = (MemberInfo)sourceFragment.Member;

                MemberExpression member = ConstantExpression.MakeMemberAccess(
                    Expression.Convert(instanceParameter, memberInfo.DeclaringType),
                    memberInfo);

                if (sourceFragment != lastSourceFragment)
                {
                    // Iterate into the member.
                    targetFragments.Add(
                        Expression.Assign(
                            instanceParameter,
                            Expression.Convert(member, typeof(object))));

                    // Value types cannot represent a null reference.
                    if (sourceFragment.Type.IsClass)
                    {
                        targetFragments.Add(
                            Expression.IfThen(
                                Expression.Equal(instanceParameter, Expression.Constant(null)),
                                Expression.Goto(useDefaultLabel)));
                    }
                }
                else
                {
                    // The value of the final member is the actual result.
                    targetFragments.Add(
                        Expression.Assign(
                            resultVariable,
                            Expression.Convert(member, typeof(TResult))));
                }
            }

            targetFragments.Add(Expression.Goto(returnLabel));
            targetFragments.Add(Expression.Label(useDefaultLabel));
            targetFragments.Add(Expression.Assign(resultVariable, Expression.Default(typeof(TResult))));
            targetFragments.Add(Expression.Label(returnLabel));

            targetFragments.Add(resultVariable);

            Expression finalExpression = Expression.Block(new[] { resultVariable }, targetFragments);

            return(Expression.Lambda <Func <TSource, TResult> >(finalExpression, instanceParameter).Compile());
        }