Example #1
0
        private static string GetIndexerInvocation([NotNull] Expression expression,
                                                   [NotNull] ParameterExpression[] parameters)
        {
            var converted     = Expression.Convert(expression, typeof(object));
            var fakeParameter = Expression.Parameter(typeof(object), null);
            var lambda        = Expression.Lambda <Func <object, object> >(converted, fakeParameter);
            Func <object, object> func;

            try
            {
                func = CachedExpressionCompiler.Process(lambda);
            }
            catch (InvalidOperationException ex)
            {
                throw new InvalidOperationException(
                          Resources.FormatExpressionHelper_InvalidIndexerExpression(expression, parameters[0].Name),
                          ex);
            }

            return("[" + Convert.ToString(func(null), CultureInfo.InvariantCulture) + "]");
        }
        public static ModelExplorer FromLambdaExpression <TModel, TResult>(
            [NotNull] Expression <Func <TModel, TResult> > expression,
            [NotNull] ViewDataDictionary <TModel> viewData,
            IModelMetadataProvider metadataProvider)
        {
            string propertyName    = null;
            Type   containerType   = null;
            var    legalExpression = false;

            // Need to verify the expression is valid; it needs to at least end in something
            // that we can convert to a meaningful string for model binding purposes

            switch (expression.Body.NodeType)
            {
            case ExpressionType.ArrayIndex:
                // ArrayIndex always means a single-dimensional indexer;
                // multi-dimensional indexer is a method call to Get().
                legalExpression = true;
                break;

            case ExpressionType.Call:
                // Only legal method call is a single argument indexer/DefaultMember call
                legalExpression = ExpressionHelper.IsSingleArgumentIndexer(expression.Body);
                break;

            case ExpressionType.MemberAccess:
                // Property/field access is always legal
                var memberExpression = (MemberExpression)expression.Body;
                propertyName    = memberExpression.Member is PropertyInfo ? memberExpression.Member.Name : null;
                containerType   = memberExpression.Expression.Type;
                legalExpression = true;
                break;

            case ExpressionType.Parameter:
                // Parameter expression means "model => model", so we delegate to FromModel
                return(FromModel(viewData, metadataProvider));
            }

            if (!legalExpression)
            {
                throw new InvalidOperationException(Resources.TemplateHelpers_TemplateLimitations);
            }

            Func <object, object> modelAccessor = (container) =>
            {
                try
                {
                    return(CachedExpressionCompiler.Process(expression)((TModel)container));
                }
                catch (NullReferenceException)
                {
                    return(null);
                }
            };

            ModelMetadata metadata;

            if (propertyName == null)
            {
                // Ex:
                //    m => 5 (arbitrary expression)
                //    m => foo (arbitrary expression)
                //    m => m.Widgets[0] (expression ending with non-property-access)
                metadata = metadataProvider.GetMetadataForType(typeof(TResult));
            }
            else
            {
                // Ex:
                //    m => m.Color (simple property access)
                //    m => m.Color.Red (nested property access)
                //    m => m.Widgets[0].Size (expression ending with property-access)
                metadata = metadataProvider.GetMetadataForType(containerType).Properties[propertyName];
            }

            return(viewData.ModelExplorer.GetExplorerForExpression(metadata, modelAccessor));
        }
Example #3
0
        public static ModelMetadata FromLambdaExpression <TParameter, TValue>(
            [NotNull] Expression <Func <TParameter, TValue> > expression,
            [NotNull] ViewDataDictionary <TParameter> viewData,
            IModelMetadataProvider metadataProvider)
        {
            string propertyName    = null;
            Type   containerType   = null;
            var    legalExpression = false;

            // Need to verify the expression is valid; it needs to at least end in something
            // that we can convert to a meaningful string for model binding purposes

            switch (expression.Body.NodeType)
            {
            case ExpressionType.ArrayIndex:
                // ArrayIndex always means a single-dimensional indexer;
                // multi-dimensional indexer is a method call to Get().
                legalExpression = true;
                break;

            case ExpressionType.Call:
                // Only legal method call is a single argument indexer/DefaultMember call
                legalExpression = ExpressionHelper.IsSingleArgumentIndexer(expression.Body);
                break;

            case ExpressionType.MemberAccess:
                // Property/field access is always legal
                var memberExpression = (MemberExpression)expression.Body;
                propertyName    = memberExpression.Member is PropertyInfo ? memberExpression.Member.Name : null;
                containerType   = memberExpression.Expression.Type;
                legalExpression = true;
                break;

            case ExpressionType.Parameter:
                // Parameter expression means "model => model", so we delegate to FromModel
                return(FromModel(viewData, metadataProvider));
            }

            if (!legalExpression)
            {
                throw new InvalidOperationException(Resources.TemplateHelpers_TemplateLimitations);
            }

            var           container     = viewData.Model;
            Func <object> modelAccessor = () =>
            {
                try
                {
                    return(CachedExpressionCompiler.Process(expression)(container));
                }
                catch (NullReferenceException)
                {
                    return(null);
                }
            };

            return(GetMetadataFromProvider(
                       modelAccessor,
                       typeof(TValue),
                       propertyName,
                       containerType,
                       metadataProvider));
        }