Esempio n. 1
0
            protected override Expression VisitMemberAccess(MemberExpression m)
            {
                base.VisitMemberAccess(m);
                ModelStep step;

                if (m.Expression != null && steps.TryGetValue(m.Expression, out step) && !(step.Property is ModelValueProperty))
                {
                    // Get the model type of the parent expression
                    var type = step.Property == null ? path.RootType : ((ModelReferenceProperty)step.Property).PropertyType;

                    // Determine if the member access represents a property on the model type
                    var property = type.Properties[m.Member.Name];

                    // If the property exists on the model type, create and record a new step
                    if (property != null)
                    {
                        var nextStep = step.NextSteps.FirstOrDefault(s => s.Property == property);
                        if (nextStep == null)
                        {
                            nextStep = new ModelStep(path)
                            {
                                Property = property, PreviousStep = step
                            };
                            step.NextSteps.Add(nextStep);
                        }
                        steps.Add(m, nextStep);
                    }
                }
                return(m);
            }
Esempio n. 2
0
            protected override Expression VisitModelParameter(ModelExpression.ModelParameterExpression p)
            {
                // Add the root step
                if (rootStep == null)
                {
                    rootStep = new ModelStep(path);
                    steps.Add(p, rootStep);
                }

                return(p);
            }
Esempio n. 3
0
 /// <summary>
 /// Safely removes an invalid step from a path.
 /// </summary>
 /// <param name="step"></param>
 static void RemoveStep(ModelStep step)
 {
     // Remove steps that do not lead to the end of the path
     if (step.Property != null && !step.NextSteps.Any())
     {
         var previousStep = step;
         while (previousStep != null && !previousStep.NextSteps.Any())
         {
             previousStep.NextSteps.Remove(previousStep);
             previousStep = previousStep.PreviousStep;
         }
     }
 }
Esempio n. 4
0
            protected override Expression VisitModelMember(ModelExpression.ModelMemberExpression m)
            {
                base.VisitModelMember(m);
                ModelStep step;

                if (steps.TryGetValue(m.Expression, out step) && !(step.Property is ModelValueProperty))
                {
                    // Get the model type of the parent expression
                    var type = step.Property == null ? path.RootType : ((ModelReferenceProperty)step.Property).PropertyType;

                    // Make sure the type of the expression matches the declaring type of the property
                    if (type != m.Property.DeclaringType && !m.Property.DeclaringType.IsSubType(type))
                    {
                        return(m);
                    }

                    // Determine if the member access represents a property on the model type
                    var property = m.Property;

                    // Create and record a new step
                    var nextStep = step.NextSteps.FirstOrDefault(s => s.Property == property);
                    if (nextStep == null)
                    {
                        nextStep = new ModelStep(path)
                        {
                            Property = property, PreviousStep = step
                        };
                        step.NextSteps.Add(nextStep);
                    }
                    if (!steps.ContainsKey(m))
                    {
                        steps.Add(m, nextStep);
                    }
                }
                return(m);
            }
Esempio n. 5
0
        /// <summary>
        /// Creates a new <see cref="ModelPath"/> instance for the specified root <see cref="ModelType"/>
        /// and path string.
        /// </summary>
        /// <param name="rootType"></param>
        /// <param name="path"></param>
        internal static ModelPath CreatePath(ModelType rootType, string path)
        {
            // Create the new path
            ModelPath newPath = new ModelPath()
            {
                RootType = rootType
            };

            // Create a temporary root step
            var root = new ModelStep(newPath);

            var steps = new List <ModelStep>()
            {
                root
            };
            var stack = new Stack <List <ModelStep> >();

            int expectedTokenStart = 0;

            var tokenMatches = pathParser.Matches(path);
            int tokenIndex   = 0;

            foreach (Match tokenMatch in tokenMatches)
            {
                // ensure there are no gaps between tokens except for whitespace
                if (tokenMatch.Index != expectedTokenStart && path.Substring(expectedTokenStart, tokenMatch.Index - expectedTokenStart - 1).Trim() != "")
                {
                    return(null);                    // throw new ArgumentException("The specified path, '" + path + "', is not valid. Character " + (expectedTokenStart));
                }
                expectedTokenStart = tokenMatch.Index + tokenMatch.Length;

                var token = tokenMatch.Value;
                switch (token[0])
                {
                case '{':
                    stack.Push(steps);
                    break;

                case '}':
                    steps = stack.Pop();
                    break;

                case ',':
                    steps = stack.Peek();
                    break;

                case '.':
                    break;

                case '<':
                    var filter = rootType.Context.GetModelType(token.Substring(1, token.Length - 2));
                    foreach (var step in steps)
                    {
                        if (step.Property is ModelReferenceProperty &&
                            (((ModelReferenceProperty)step.Property).PropertyType == filter ||
                             ((ModelReferenceProperty)step.Property).PropertyType.IsSubType(filter)))
                        {
                            step.Filter = filter;
                        }
                        else
                        {
                            RemoveStep(step);
                        }
                    }
                    break;

                default:

                    // Get the property name for the next step
                    var propertyName = token;

                    // Track the next steps
                    var nextSteps = new List <ModelStep>();


                    // Process each of the current steps
                    foreach (var step in steps)
                    {
                        // Ensure the current step is a valid reference property
                        if (step.Property != null && step.Property is ModelValueProperty)
                        {
                            return(null);                                    // throw new ArgumentException("Property '" + step.Property.Name + "' is a value property and cannot have child properties specified.");
                        }
                        // Get the type of the current step
                        var currentType = step.Property != null ? ((ModelReferenceProperty)step.Property).PropertyType : step.Path.RootType;
                        if (step.Filter != null)
                        {
                            if (step.Filter != currentType && !currentType.IsSubType(step.Filter))
                            {
                                return(null);                                        // throw new ArgumentException("Filter type '" + step.Filter.Name + "' is not a valid subtype of '" + currentType.Name + "'.");
                            }
                            currentType = step.Filter;
                        }

                        // Process the current and all subtypes, honoring any specified type filters
                        foreach (var type in currentType.GetDescendentsInclusive())
                        {
                            // Get the current property
                            var property = type.Properties[propertyName];

                            // Ensure the property is valid
                            if (property == null || property.IsStatic || (property.DeclaringType != type && type != currentType && currentType.Properties[propertyName] != null))
                            {
                                continue;
                            }

                            // Look ahead to see if this step is filtered
                            filter = tokenIndex < tokenMatches.Count - 1 && tokenMatches[tokenIndex + 1].Value.StartsWith("<") ?
                                     rootType.Context.GetModelType(tokenMatches[tokenIndex + 1].Value.Substring(1, tokenMatches[tokenIndex + 1].Length - 2)) :
                                     null;

                            // See if the step already exists for this property and filter or needs to be created
                            var nextStep = step.NextSteps.Where(s => s.Property == property && s.Filter == filter).FirstOrDefault();
                            if (nextStep == null)
                            {
                                nextStep = new ModelStep(newPath)
                                {
                                    Property = property, Filter = filter, PreviousStep = step.Property != null ? step : null
                                };
                                step.NextSteps.Add(nextStep);
                            }
                            nextSteps.Add(nextStep);
                        }

                        // Remove steps that do not lead to the end of the path
                        RemoveStep(step);
                    }

                    // Immediately exit if no steps were found matching the requested path
                    if (nextSteps.Count == 0)
                    {
                        return(null);
                    }

                    steps = nextSteps;
                    break;
                }

                ++tokenIndex;
            }

            // Throw an exception if there are unmatched property group delimiters
            if (stack.Count > 0)
            {
                throw new ArgumentException("Unclosed '{' in path: " + path, "path");
            }

            // Return null if the path was not valid
            if (!root.NextSteps.Any())
            {
                return(null);
            }

            // Otherwise, finish initializing and return the new path
            newPath.FirstSteps = root.NextSteps;
            newPath.Path       = path;
            return(newPath);
        }
Esempio n. 6
0
            protected override Expression VisitParameter(ParameterExpression p)
            {
                base.VisitParameter(p);

                // Add the root step
                if (rootStep == null)
                {
                    rootStep = new ModelStep(path);
                    steps.Add(p, rootStep);
                }

                return p;
            }
Esempio n. 7
0
            protected override Expression VisitModelMember(ModelExpression.ModelMemberExpression m)
            {
                base.VisitModelMember(m);
                ModelStep step;
                if (steps.TryGetValue(m.Expression, out step) && !(step.Property is ModelValueProperty))
                {
                    // Get the model type of the parent expression
                    var type = step.Property == null ? path.RootType : ((ModelReferenceProperty)step.Property).PropertyType;

                    // Make sure the type of the expression matches the declaring type of the property
                    if (type != m.Property.DeclaringType && !m.Property.DeclaringType.IsSubType(type))
                        return m;

                    // Determine if the member access represents a property on the model type
                    var property = m.Property;

                    // Create and record a new step
                    var nextStep = step.NextSteps.FirstOrDefault(s => s.Property == property);
                    if (nextStep == null)
                    {
                        nextStep = new ModelStep(path) { Property = property, PreviousStep = step };
                        step.NextSteps.Add(nextStep);
                    }
                    if (!steps.ContainsKey(m))
                        steps.Add(m, nextStep);
                }
                return m;
            }
Esempio n. 8
0
            protected override Expression VisitMemberAccess(MemberExpression m)
            {
                base.VisitMemberAccess(m);
                ModelStep step;
                if (m.Expression != null && steps.TryGetValue(m.Expression, out step) && !(step.Property is ModelValueProperty))
                {
                    // Get the model type of the parent expression
                    var type = step.Property == null ? path.RootType : ((ModelReferenceProperty)step.Property).PropertyType;

                    // Determine if the member access represents a property on the model type
                    var property = type.Properties[m.Member.Name];

                    // If the property exists on the model type, create and record a new step
                    if (property != null)
                    {
                        var nextStep = step.NextSteps.FirstOrDefault(s => s.Property == property);
                        if (nextStep == null)
                        {
                            nextStep = new ModelStep(path) { Property = property, PreviousStep = step };
                            step.NextSteps.Add(nextStep);
                        }
                        steps.Add(m, nextStep);
                    }
                }
                return m;
            }
Esempio n. 9
0
 /// <summary>
 /// Safely removes an invalid step from a path.
 /// </summary>
 /// <param name="step"></param>
 static void RemoveStep(ModelStep step)
 {
     // Remove steps that do not lead to the end of the path
     if (step.Property != null && !step.NextSteps.Any())
     {
         var previousStep = step;
         while (previousStep != null && !previousStep.NextSteps.Any())
         {
             previousStep.NextSteps.Remove(previousStep);
             previousStep = previousStep.PreviousStep;
         }
     }
 }
Esempio n. 10
0
        /// <summary>
        /// Creates a new <see cref="ModelPath"/> instance for the specified root <see cref="ModelType"/>
        /// and path string.
        /// </summary>
        /// <param name="rootType"></param>
        /// <param name="path"></param>
        internal static ModelPath CreatePath(ModelType rootType, string path)
        {
            // Create the new path
            ModelPath newPath = new ModelPath()
            {
                RootType = rootType
            };

            // Create a temporary root step
            var root = new ModelStep(newPath);

            var steps = new List<ModelStep>() { root };
            var stack = new Stack<List<ModelStep>>();

            int expectedTokenStart = 0;

            var tokenMatches = pathParser.Matches(path);
            int tokenIndex = 0;
            foreach (Match tokenMatch in tokenMatches)
            {
                // ensure there are no gaps between tokens except for whitespace
                if (tokenMatch.Index != expectedTokenStart && path.Substring(expectedTokenStart, tokenMatch.Index - expectedTokenStart - 1).Trim() != "" )
                    return null; // throw new ArgumentException("The specified path, '" + path + "', is not valid. Character " + (expectedTokenStart));

                expectedTokenStart = tokenMatch.Index + tokenMatch.Length;

                var token = tokenMatch.Value;
                switch (token[0])
                {
                    case '{':
                        stack.Push(steps);
                        break;
                    case '}':
                        steps = stack.Pop();
                        break;
                    case ',':
                        steps = stack.Peek();
                        break;
                    case '.':
                        break;
                    case '<':
                        var filter = rootType.Context.GetModelType(token.Substring(1, token.Length - 2));
                        foreach (var step in steps)
                        {
                            if (step.Property is ModelReferenceProperty &&
                                (((ModelReferenceProperty)step.Property).PropertyType == filter ||
                                ((ModelReferenceProperty)step.Property).PropertyType.IsSubType(filter)))
                                step.Filter = filter;
                            else
                                RemoveStep(step);
                        }
                        break;
                    default:

                        // Get the property name for the next step
                        var propertyName = token;

                        // Track the next steps
                        var nextSteps = new List<ModelStep>();

                        // Process each of the current steps
                        foreach (var step in steps)
                        {
                            // Ensure the current step is a valid reference property
                            if (step.Property != null && step.Property is ModelValueProperty)
                                return null; // throw new ArgumentException("Property '" + step.Property.Name + "' is a value property and cannot have child properties specified.");

                            // Get the type of the current step
                            var currentType = step.Property != null ? ((ModelReferenceProperty)step.Property).PropertyType : step.Path.RootType;
                            if (step.Filter != null)
                            {
                                if (step.Filter != currentType && !currentType.IsSubType(step.Filter))
                                    return null; // throw new ArgumentException("Filter type '" + step.Filter.Name + "' is not a valid subtype of '" + currentType.Name + "'.");
                                currentType = step.Filter;
                            }

                            // Process the current and all subtypes, honoring any specified type filters
                            foreach (var type in currentType.GetDescendentsInclusive())
                            {
                                // Get the current property
                                var property = type.Properties[propertyName];

                                // Ensure the property is valid
                                if (property == null || property.IsStatic || (property.DeclaringType != type && type != currentType && currentType.Properties[propertyName] != null))
                                    continue;

                                // Look ahead to see if this step is filtered
                                filter = tokenIndex < tokenMatches.Count - 1 && tokenMatches[tokenIndex + 1].Value.StartsWith("<") ?
                                    rootType.Context.GetModelType(tokenMatches[tokenIndex + 1].Value.Substring(1, tokenMatches[tokenIndex + 1].Length - 2)) :
                                    null;

                                // See if the step already exists for this property and filter or needs to be created
                                var nextStep = step.NextSteps.Where(s => s.Property == property && s.Filter == filter).FirstOrDefault();
                                if (nextStep == null)
                                {
                                    nextStep = new ModelStep(newPath) { Property = property, Filter = filter, PreviousStep = step.Property != null ? step : null };
                                    step.NextSteps.Add(nextStep);
                                }
                                nextSteps.Add(nextStep);
                            }

                            // Remove steps that do not lead to the end of the path
                            RemoveStep(step);
                        }

                        // Immediately exit if no steps were found matching the requested path
                        if (nextSteps.Count == 0)
                            return null;

                        steps = nextSteps;
                        break;
                }

                ++tokenIndex;
            }

            // Throw an exception if there are unmatched property group delimiters
            if (stack.Count > 0)
                throw new ArgumentException("Unclosed '{' in path: " + path, "path");

            // Return null if the path was not valid
            if (!root.NextSteps.Any())
                return null;

            // Otherwise, finish initializing and return the new path
            newPath.FirstSteps = root.NextSteps;
            newPath.Path = path;
            return newPath;
        }