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)); }