/// <summary> /// Find all properties from the model and fill this.properties. /// </summary> public void FindAllProperties(Model model) { this.model = model; this.properties.Clear(); if (this.model != null) { foreach (PropertyInfo property in this.model.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy)) { // Properties must have a [Description], not be called Name, and be read/write. bool hasDescription = property.IsDefined(typeof(DescriptionAttribute), false); bool includeProperty = hasDescription && property.Name != "Name" && property.CanRead && property.CanWrite; // Only allow lists that are double[], int[] or string[] if (includeProperty && property.PropertyType.GetInterface("IList") != null) { includeProperty = property.PropertyType == typeof(double[]) || property.PropertyType == typeof(int[]) || property.PropertyType == typeof(string[]); } if (includeProperty) { this.properties.Add(new VariableProperty(this.model, property)); } if (property.PropertyType == typeof(DataTable)) { VariableProperty vp = new VariableProperty(this.model, property); DataTable dt = vp.Value as DataTable; this.grid.DataSource = dt; } } } }
/// <summary> /// Set the value of the specified property /// </summary> /// <param name="property">The property to set the value of</param> /// <param name="value">The value to set the property to</param> private void SetPropertyValue(VariableProperty property, object value) { if (property.DataType.IsArray && value != null) { string[] stringValues = value.ToString().Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); if (property.DataType == typeof(double[])) { value = MathUtilities.StringsToDoubles(stringValues); } else if (property.DataType == typeof(int[])) { value = MathUtilities.StringsToDoubles(stringValues); } else if (property.DataType == typeof(string[])) { value = stringValues; } else { throw new ApsimXException(this.model, "Invalid property type: " + property.DataType.ToString()); } } else if (typeof(ICrop).IsAssignableFrom(property.DataType)) { value = Apsim.Find(this.model, value.ToString()) as ICrop; } else if (property.DataType.IsEnum) { value = Enum.Parse(property.DataType, value.ToString()); } Commands.ChangeProperty cmd = new Commands.ChangeProperty(this.model, property.Name, value); this.explorerPresenter.CommandHistory.Add(cmd, true); }
/// <summary> /// Get the value of a variable or model. /// </summary> /// <param name="namePath">The name of the object to return</param> /// <param name="ignoreCase">If true, ignore case when searching for the object or property</param> /// <returns>The found object or null if not found</returns> private IVariable GetInternal(string namePath, bool ignoreCase = true) { IModel relativeTo = relativeToModel; string cacheKey = namePath; StringComparison compareType = ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; // Look in cache first. object value = null; if (cache.ContainsKey(cacheKey)) { value = cache[cacheKey]; } if (value != null) { return(value as IVariable); } IVariable returnVariable = null; if (namePath == null || namePath.Length == 0) { return(null); } else if (namePath[0] != '.' && namePath.Replace("()", "").IndexOfAny("(+*/".ToCharArray()) != -1) { // expression - need a better way of detecting an expression returnVariable = new VariableExpression(namePath, relativeTo as Model); } else { // Remove a square bracketed model name and change our relativeTo model to // the referenced model. if (namePath.StartsWith("[")) { int posCloseBracket = namePath.IndexOf(']'); if (posCloseBracket == -1) { return(null); } string modelName = namePath.Substring(1, posCloseBracket - 1); namePath = namePath.Remove(0, posCloseBracket + 1); Model foundModel = Apsim.Find(relativeTo, modelName) as Model; if (foundModel == null) { // Didn't find a model with a name matching the square bracketed string so // now try and look for a model with a type matching the square bracketed string. Type[] modelTypes = GetTypeWithoutNameSpace(modelName); if (modelTypes.Length == 1) { foundModel = Apsim.Find(relativeTo, modelTypes[0]) as Model; } } if (foundModel == null) { return(null); } else { relativeTo = foundModel; } } else if (namePath.StartsWith(".")) { // Absolute path IModel root = relativeTo; while (root.Parent != null) { root = root.Parent as Model; } relativeTo = root; int posPeriod = namePath.IndexOf('.', 1); if (posPeriod == -1) { posPeriod = namePath.Length; } namePath = namePath.Remove(0, posPeriod); if (namePath.StartsWith(".")) { namePath.Remove(1); } } // Now walk the series of '.' separated path bits, assuming the path bits // are child models. Stop when we can't find the child model. string[] namePathBits = namePath.Split(".".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); int i; for (i = 0; i < namePathBits.Length; i++) { IModel localModel = relativeTo.Children.FirstOrDefault(m => m.Name.Equals(namePathBits[i], compareType)); if (localModel == null) { break; } else { relativeTo = localModel as Model; } } // At this point there are only 2 possibilities. We have encountered a // PropertyInfo or the path is invalid. // We now need to loop through the remaining path bits and keep track of each // section of the path as each section will have to be evaulated everytime a // a get is done for this path. // The variable 'i' will point to the name path that cannot be found as a model. object relativeToObject = relativeTo; List <IVariable> properties = new List <IVariable>(); properties.Add(new VariableObject(relativeTo)); for (int j = i; j < namePathBits.Length; j++) { // look for an array specifier e.g. sw[2] string arraySpecifier = null; if (namePathBits[j].Contains("[")) { arraySpecifier = StringUtilities.SplitOffBracketedValue(ref namePathBits[j], '[', ']'); } // Look for either a property or a child model. IModel localModel = null; if (relativeToObject == null) { return(null); } PropertyInfo propertyInfo = relativeToObject.GetType().GetProperty(namePathBits[j]); if (propertyInfo == null && ignoreCase) // If not found, try using a case-insensitive search { propertyInfo = relativeToObject.GetType().GetProperty(namePathBits[j], BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.IgnoreCase); } if (relativeToObject is IFunction && namePathBits[j] == "Value()") { MethodInfo method = relativeTo.GetType().GetMethod("Value"); properties.Add(new VariableMethod(relativeTo, method)); } else if (propertyInfo == null && relativeToObject is Model) { // Not a property, may be a child model. localModel = (relativeToObject as IModel).Children.FirstOrDefault(m => m.Name.Equals(namePathBits[i], compareType)); if (localModel == null) { return(null); } properties.Add(new VariableObject(localModel)); relativeToObject = localModel; } else if (propertyInfo != null) { VariableProperty property = new VariableProperty(relativeToObject, propertyInfo, arraySpecifier); properties.Add(property); relativeToObject = property.Value; } else if (relativeToObject is IList) { // Special case: we are trying to get a property of an array(IList). In this case // we want to return the property value for all items in the array. VariableProperty property = new VariableProperty(relativeToObject, namePathBits[j]); properties.Add(property); relativeToObject = property.Value; } else { return(null); } } // We now have a list of IVariable instances that can be evaluated to // produce a return value for the given path. Wrap the list into an IVariable. returnVariable = new VariableComposite(namePath, properties); } // Add variable to cache. cache.Add(cacheKey, returnVariable); return(returnVariable); }
/// <summary> /// Get the value of a variable or model. /// </summary> /// <param name="namePath">The name of the object to return</param> /// <param name="relativeTo">The model calling this method</param> /// <param name="ignoreCase">If true, ignore case when searching for the object or property</param> /// <returns>The found object or null if not found</returns> public IVariable GetInternal(string namePath, Model relativeTo, bool ignoreCase = false) { Model relativeToModel = relativeTo; string cacheKey = namePath; StringComparison compareType = ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; // Look in cache first. object value = GetFromCache(cacheKey, relativeToModel); if (value != null) { return value as IVariable; } IVariable returnVariable = null; if (namePath == null || namePath.Length == 0) { return null; } else if (namePath[0] != '.' && namePath[0] != '.' && namePath.IndexOfAny("(+*/".ToCharArray()) != -1) { // expression - need a better way of detecting an expression returnVariable = new VariableExpression(namePath, relativeToModel); } else { // Remove a square bracketed model name and change our relativeTo model to // the referenced model. if (namePath.StartsWith("[")) { int posCloseBracket = namePath.IndexOf(']'); if (posCloseBracket == -1) { return null; } string modelName = namePath.Substring(1, posCloseBracket - 1); namePath = namePath.Remove(0, posCloseBracket + 1); Model foundModel = this.Find(modelName, relativeToModel); if (foundModel == null) { // Didn't find a model with a name matching the square bracketed string so // now try and look for a model with a type matching the square bracketed string. Type[] modelTypes = GetTypeWithoutNameSpace(modelName); if (modelTypes.Length == 1) foundModel = this.Find(modelTypes[0], relativeToModel); } if (foundModel == null) return null; else relativeToModel = foundModel; } else if (namePath.StartsWith(".")) { // Absolute path Model root = relativeToModel; while (root.Parent != null) { root = root.Parent as Model; } relativeToModel = root; int posPeriod = namePath.IndexOf('.', 1); if (posPeriod == -1) { posPeriod = namePath.Length; } namePath = namePath.Remove(0, posPeriod); if (namePath.StartsWith(".")) { namePath.Remove(1); } } // Now walk the series of '.' separated path bits, assuming the path bits // are child models. Stop when we can't find the child model. string[] namePathBits = namePath.Split(".".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); int i; for (i = 0; i < namePathBits.Length; i++) { IModel localModel = relativeToModel.Children.FirstOrDefault(m => m.Name.Equals(namePathBits[i], compareType)); if (localModel == null) { break; } else { relativeToModel = localModel as Model; } } // At this point there are only 2 possibilities. We have encountered a // PropertyInfo or the path is invalid. // We now need to loop through the remaining path bits and keep track of each // section of the path as each section will have to be evaulated everytime a // a get is done for this path. // The variable 'i' will point to the name path that cannot be found as a model. object relativeToObject = relativeToModel; List<IVariable> properties = new List<IVariable>(); properties.Add(new VariableObject(relativeToModel)); for (int j = i; j < namePathBits.Length; j++) { // look for an array specifier e.g. sw[2] string arraySpecifier = null; if (namePathBits[j].Contains("[")) { arraySpecifier = StringUtilities.SplitOffBracketedValue(ref namePathBits[j], '[', ']'); } // Look for either a property or a child model. IModel localModel = null; if (relativeToObject == null) return null; PropertyInfo propertyInfo = relativeToObject.GetType().GetProperty(namePathBits[j]); if (propertyInfo == null && ignoreCase) // If not found, try using a case-insensitive search propertyInfo = relativeToObject.GetType().GetProperty(namePathBits[j], BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.IgnoreCase); if (propertyInfo == null && relativeToObject is Model) { // Not a property, may be a child model. localModel = (relativeToObject as IModel).Children.FirstOrDefault(m => m.Name.Equals(namePathBits[i], compareType)); if (localModel == null) { return null; } properties.Add(new VariableObject(localModel)); relativeToObject = localModel; } else if (propertyInfo != null) { VariableProperty property = new VariableProperty(relativeToObject, propertyInfo, arraySpecifier); properties.Add(property); relativeToObject = property.Value; } else if (relativeToObject is IList) { // Special case: we are trying to get a property of an array(IList). In this case // we want to return the property value for all items in the array. VariableProperty property = new VariableProperty(relativeToObject, namePathBits[j]); properties.Add(property); relativeToObject = property.Value; } else { return null; } } // We now have a list of IVariable instances that can be evaluated to // produce a return value for the given path. Wrap the list into an IVariable. returnVariable = new VariableComposite(namePath, properties); } // Add variable to cache. AddToCache(cacheKey, relativeTo, returnVariable); return returnVariable; }
/// <summary> /// The view is asking for variable names for its intellisense. /// </summary> public static List<ContextItem> ExamineTypeForContextItems(Type atype, bool properties, bool methods, bool events) { List<ContextItem> allItems = new List<ContextItem>(); // find the properties and methods if (atype != null) { if (properties) { foreach (PropertyInfo property in atype.GetProperties(BindingFlags.Instance | BindingFlags.Public)) { VariableProperty var = new VariableProperty(atype, property); NeedContextItemsArgs.ContextItem item = new NeedContextItemsArgs.ContextItem(); item.Name = var.Name; item.IsProperty = true; item.IsEvent = false; item.IsWriteable = !var.IsReadOnly; item.TypeName = var.DataType.Name; item.Descr = var.Description; item.Units = var.Units; allItems.Add(item); } } if (methods) { foreach (MethodInfo method in atype.GetMethods(BindingFlags.Instance | BindingFlags.Public)) { if (!method.Name.StartsWith("get_") && !method.Name.StartsWith("set_")) { DescriptionAttribute descriptionAttribute = ReflectionUtilities.GetAttribute(atype, typeof(DescriptionAttribute), false) as DescriptionAttribute; NeedContextItemsArgs.ContextItem item = new NeedContextItemsArgs.ContextItem(); item.Name = method.Name; item.IsProperty = false; item.IsEvent = true; item.IsWriteable = false; item.TypeName = method.ReturnType.Name; if (descriptionAttribute != null) item.Descr = descriptionAttribute.ToString(); item.Units = string.Empty; // build a parameter string representation ParameterInfo[] allparams = method.GetParameters(); StringBuilder paramText = new StringBuilder("( "); if (allparams.Count() > 0) { for (int p = 0; p < allparams.Count(); p++) { ParameterInfo parameter = allparams[p]; paramText.Append(parameter.ParameterType.Name + " " + parameter.Name); if (p < allparams.Count() - 1) paramText.Append(", "); } } paramText.Append(" )"); item.ParamString = paramText.ToString(); allItems.Add(item); } } } if (events) { foreach (EventInfo evnt in atype.GetEvents(BindingFlags.Instance | BindingFlags.Public)) { NeedContextItemsArgs.ContextItem item = new NeedContextItemsArgs.ContextItem(); item.Name = evnt.Name; item.IsProperty = true; item.IsEvent = true; item.IsWriteable = false; item.TypeName = evnt.ReflectedType.Name; item.Descr = ""; item.Units = ""; allItems.Add(item); } } } allItems.Sort(delegate(ContextItem c1, ContextItem c2) { return c1.Name.CompareTo(c2.Name); }); return allItems; }
/// <summary> /// Get the value of a variable or model. /// </summary> /// <param name="namePath">The name of the object to return</param> /// <param name="ignoreCase">If true, ignore case when searching for the object or property</param> /// <returns>The found object or null if not found</returns> private IVariable GetInternal(string namePath, bool ignoreCase = true) { IModel relativeTo = relativeToModel; string cacheKey = namePath; StringComparison compareType = ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; // Look in cache first. object value = null; if (cache.ContainsKey(cacheKey)) { value = cache[cacheKey]; } if (value != null) { return(value as IVariable); } IVariable returnVariable = null; if (namePath == null || namePath.Length == 0) { return(null); } else if (namePath[0] != '.' && (namePath.Replace("()", "").IndexOfAny("+*/".ToCharArray()) != -1 | (namePath.IndexOfAny("(".ToCharArray()) >= 0 && namePath.Substring(0, (namePath.IndexOf('(') >= 0? namePath.IndexOf('(') : 0)).IndexOfAny("[.".ToCharArray()) == -1))) { // expression - need a better way of detecting an expression returnVariable = new VariableExpression(namePath, relativeTo as Model); } else { namePath = namePath.Replace("Value()", "Value()."); // Remove a square bracketed model name and change our relativeTo model to // the referenced model. if (namePath.StartsWith("[")) { int posCloseBracket = namePath.IndexOf(']'); if (posCloseBracket == -1) { return(null); } string modelName = namePath.Substring(1, posCloseBracket - 1); namePath = namePath.Remove(0, posCloseBracket + 1); Model foundModel = Apsim.Find(relativeTo, modelName) as Model; if (foundModel == null) { // Didn't find a model with a name matching the square bracketed string so // now try and look for a model with a type matching the square bracketed string. Type[] modelTypes = GetTypeWithoutNameSpace(modelName); if (modelTypes.Length == 1) { foundModel = Apsim.Find(relativeTo, modelTypes[0]) as Model; } } if (foundModel == null) { return(null); } else { relativeTo = foundModel; } } else if (namePath.StartsWith(".")) { // Absolute path IModel root = relativeTo; while (root.Parent != null) { root = root.Parent as Model; } relativeTo = root; int posPeriod = namePath.IndexOf('.', 1); if (posPeriod == -1) { posPeriod = namePath.Length; } namePath = namePath.Remove(0, posPeriod); if (namePath.StartsWith(".")) { namePath.Remove(1); } } // Now walk the series of '.' separated path bits, assuming the path bits // are child models. Stop when we can't find the child model. string[] namePathBits = namePath.Split(".".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); int i; for (i = 0; i < namePathBits.Length; i++) { IModel localModel = relativeTo.Children.FirstOrDefault(m => m.Name.Equals(namePathBits[i], compareType) && m.Enabled); if (localModel == null) { break; } else { relativeTo = localModel as Model; } } // At this point there are only 2 possibilities. We have encountered a // PropertyInfo/MethodInfo or the path is invalid. // We now need to loop through the remaining path bits and keep track of each // section of the path as each section will have to be evaulated everytime a // a get is done for this path. // The variable 'i' will point to the name path that cannot be found as a model. object relativeToObject = relativeTo; List <IVariable> properties = new List <IVariable>(); properties.Add(new VariableObject(relativeTo)); for (int j = i; j < namePathBits.Length; j++) { // look for an array specifier e.g. sw[2] string arraySpecifier = null; if (namePathBits[j].Contains("[")) { arraySpecifier = StringUtilities.SplitOffBracketedValue(ref namePathBits[j], '[', ']'); } // Look for either a property or a child model. IModel localModel = null; if (relativeToObject == null) { return(null); } // Check property info PropertyInfo propertyInfo = relativeToObject.GetType().GetProperty(namePathBits[j]); if (propertyInfo == null && ignoreCase) // If not found, try using a case-insensitive search { propertyInfo = relativeToObject.GetType().GetProperty(namePathBits[j], BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.IgnoreCase); } // If not property info // Check method info MethodInfo methodInfo = null; List <object> argumentsList = null; if (propertyInfo == null) { if (namePathBits[j].IndexOf('(') > 0) { relativeToObject.GetType().GetMethod(namePathBits[j].Substring(0, namePathBits[j].IndexOf('('))); if (methodInfo == null && ignoreCase) // If not found, try using a case-insensitive search { methodInfo = relativeToObject.GetType().GetMethod(namePathBits[j].Substring(0, namePathBits[j].IndexOf('(')), BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.IgnoreCase); } } if (methodInfo != null) { // get arguments and store in VariableMethod string args = namePathBits[j].Substring(namePathBits[j].IndexOf('(')); args = args.Substring(0, args.IndexOf(')')); args = args.Replace("(", "").Replace(")", ""); if (args.Length > 0) { argumentsList = new List <object>(); args = args.Trim('(').Trim(')'); var argList = args.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); // get arguments ParameterInfo[] pars = methodInfo.GetParameters(); for (int argid = 0; argid < argList.Length; argid++) { var cleanArg = argList[argid].Trim(' ').Trim(new char[] { '(', ')' }).Trim(' ').Trim('"'); switch (Type.GetTypeCode(pars[argid].ParameterType)) { case TypeCode.Double: argumentsList.Add(Convert.ToDouble(cleanArg, CultureInfo.InvariantCulture)); break; case TypeCode.Int32: argumentsList.Add(Convert.ToInt32(cleanArg, CultureInfo.InvariantCulture)); break; case TypeCode.String: argumentsList.Add(cleanArg); break; case TypeCode.Boolean: argumentsList.Add(Convert.ToBoolean(cleanArg, CultureInfo.InvariantCulture)); break; default: throw new ApsimXException(relativeToModel, "The type of argument (" + Type.GetTypeCode(pars[argid].ParameterType) + ") is not currently supported in Report methods"); } } } } } //if (relativeToObject is IFunction && namePathBits[j] == "Value()") //{ // MethodInfo method = relativeTo.GetType().GetMethod("Value"); // properties.Add(new VariableMethod(relativeTo, method)); //} // else if (propertyInfo == null && methodInfo == null && relativeToObject is Model) if (propertyInfo == null && methodInfo == null && relativeToObject is Model) { // Not a property, may be an unchecked method or a child model. localModel = (relativeToObject as IModel).Children.FirstOrDefault(m => m.Name.Equals(namePathBits[j], compareType)); if (localModel == null) { // Not a model return(null); } else { properties.Add(new VariableObject(localModel)); relativeToObject = localModel; } } else if (propertyInfo != null) { VariableProperty property = new VariableProperty(relativeToObject, propertyInfo, arraySpecifier); properties.Add(property); relativeToObject = property.Value; } else if (methodInfo != null) { VariableMethod method = null; if (argumentsList != null) { method = new VariableMethod(relativeToObject, methodInfo, argumentsList.ToArray <object>()); } else { method = new VariableMethod(relativeToObject, methodInfo, null); } // VariableProperty property = new VariableProperty(relativeToObject, propertyInfo, arraySpecifier); properties.Add(method); relativeToObject = method.Value; } else if (relativeToObject is IList) { // Special case: we are trying to get a property of an array(IList). In this case // we want to return the property value for all items in the array. VariableProperty property = new VariableProperty(relativeToObject, namePathBits[j]); properties.Add(property); relativeToObject = property.Value; } else { return(null); } } // We now have a list of IVariable instances that can be evaluated to // produce a return value for the given path. Wrap the list into an IVariable. returnVariable = new VariableComposite(namePath, properties); } // Add variable to cache. cache.Add(cacheKey, returnVariable); return(returnVariable); }
/// <summary> /// Get the value of a variable or model. /// </summary> /// <param name="namePath">The name of the object to return</param> /// <param name="relativeTo">The model calling this method</param> /// <returns>The found object or null if not found</returns> public IVariable GetInternal(string namePath, Model relativeTo) { Model relativeToModel = relativeTo; string cacheKey = namePath; // Look in cache first. object value = GetFromCache(cacheKey, relativeToModel); if (value != null) { return(value as IVariable); } IVariable returnVariable = null; if (namePath == null || namePath.Length == 0) { return(null); } else if (namePath[0] != '.' && namePath[0] != '.' && namePath.IndexOfAny("(+*/".ToCharArray()) != -1) { // expression - need a better way of detecting an expression returnVariable = new VariableExpression(namePath, relativeToModel); } else { // Remove a square bracketed model name and change our relativeTo model to // the referenced model. if (namePath.StartsWith("[")) { int posCloseBracket = namePath.IndexOf(']'); if (posCloseBracket == -1) { return(null); } string modelName = namePath.Substring(1, posCloseBracket - 1); namePath = namePath.Remove(0, posCloseBracket + 1); Model foundModel = this.Find(modelName, relativeToModel); if (foundModel == null) { // Didn't find a model with a name matching the square bracketed string so // now try and look for a model with a type matching the square bracketed string. Type[] modelTypes = GetTypeWithoutNameSpace(modelName); if (modelTypes.Length == 1) { foundModel = this.Find(modelTypes[0], relativeToModel); } } if (foundModel == null) { return(null); } else { relativeToModel = foundModel; } } else if (namePath.StartsWith(".")) { // Absolute path Model root = relativeToModel; while (root.Parent != null) { root = root.Parent as Model; } relativeToModel = root; int posPeriod = namePath.IndexOf('.', 1); if (posPeriod == -1) { posPeriod = namePath.Length; } namePath = namePath.Remove(0, posPeriod); if (namePath.StartsWith(".")) { namePath.Remove(1); } } // Now walk the series of '.' separated path bits, assuming the path bits // are child models. Stop when we can't find the child model. string[] namePathBits = namePath.Split(".".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); int i; for (i = 0; i < namePathBits.Length; i++) { IModel localModel = relativeToModel.Children.FirstOrDefault(m => m.Name == namePathBits[i]); if (localModel == null) { break; } else { relativeToModel = localModel as Model; } } // At this point there are only 2 possibilities. We have encountered a // PropertyInfo or the path is invalid. // We now need to loop through the remaining path bits and keep track of each // section of the path as each section will have to be evaulated everytime a // a get is done for this path. // The variable 'i' will point to the name path that cannot be found as a model. object relativeToObject = relativeToModel; List <IVariable> properties = new List <IVariable>(); properties.Add(new VariableObject(relativeToModel)); for (int j = i; j < namePathBits.Length; j++) { // look for an array specifier e.g. sw[2] string arraySpecifier = null; if (namePathBits[j].Contains("[")) { arraySpecifier = StringUtilities.SplitOffBracketedValue(ref namePathBits[j], '[', ']'); } // Look for either a property or a child model. IModel localModel = null; PropertyInfo propertyInfo = relativeToObject.GetType().GetProperty(namePathBits[j]); if (propertyInfo == null && relativeToObject is Model) { // Not a property, may be a child model. localModel = (relativeToObject as IModel).Children.FirstOrDefault(m => m.Name == namePathBits[i]); if (localModel == null) { return(null); } properties.Add(new VariableObject(localModel)); relativeToObject = localModel; } else if (propertyInfo != null) { VariableProperty property = new VariableProperty(relativeToObject, propertyInfo, arraySpecifier); properties.Add(property); relativeToObject = property.Value; } else { return(null); } } // We now have a list of IVariable instances that can be evaluated to // produce a return value for the given path. Wrap the list into an IVariable. returnVariable = new VariableComposite(namePath, properties); } // Add variable to cache. AddToCache(cacheKey, relativeTo, returnVariable); return(returnVariable); }