Exemplo n.º 1
0
 /// <summary>
 /// Internal [link] resolution algorithm.
 /// </summary>
 /// <param name="obj"></param>
 /// <param name="scope">The scoping rules to use to resolve links.</param>
 private void ResolveInternal(object obj, ScopingRules scope)
 {
     foreach (IVariable field in GetAllDeclarations(GetModel(obj),
                                                    GetModel(obj).GetType(),
                                                    BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.NonPublic | BindingFlags.Public,
                                                    allLinks: true))
     {
         LinkAttribute link = field.GetAttribute(typeof(LinkAttribute)) as LinkAttribute;
         if (link != null)
         {
             Type fieldType = field.DataType;
             if (fieldType.IsArray)
             {
                 fieldType = fieldType.GetElementType();
             }
             else if (field.DataType.Name.StartsWith("List") && field.DataType.GenericTypeArguments.Length == 1)
             {
                 fieldType = field.DataType.GenericTypeArguments[0];
             }
             List <object> matches;
             matches = services.FindAll(s => fieldType.IsAssignableFrom(s.GetType()));
             if (matches.Count == 0 && obj is IModel)
             {
                 Simulation parentSimulation = Apsim.Parent(obj as IModel, typeof(Simulation)) as Simulation;
                 if (fieldType.IsAssignableFrom(typeof(ILocator)) && parentSimulation != null)
                 {
                     matches.Add(new Locator(obj as IModel));
                 }
                 else if (fieldType.IsAssignableFrom(typeof(IEvent)) && parentSimulation != null)
                 {
                     matches.Add(new Events(obj as IModel));
                 }
             }
             if (matches.Count == 0)
             {
                 if (link is ParentLinkAttribute)
                 {
                     matches = new List <object>();
                     matches.Add(GetParent(obj, fieldType));
                 }
                 else if (link is LinkByPathAttribute)
                 {
                     var    locater = new Locater();
                     object match   = locater.Get((link as LinkByPathAttribute).Path, obj as Model);
                     if (match != null)
                     {
                         matches.Add(match);
                     }
                 }
                 else if (link.IsScoped(field))
                 {
                     matches = scope.FindAll(obj as IModel).Cast <object>().ToList();
                 }
                 else
                 {
                     matches = GetChildren(obj);
                 }
             }
             matches.RemoveAll(match => !fieldType.IsAssignableFrom(GetModel(match).GetType()));
             if (link.UseNameToMatch(field))
             {
                 matches.RemoveAll(match => !StringUtilities.StringsAreEqual(GetName(match), field.Name));
             }
             if (field.DataType.IsArray)
             {
                 Array array = Array.CreateInstance(fieldType, matches.Count);
                 for (int i = 0; i < matches.Count; i++)
                 {
                     array.SetValue(GetModel(matches[i]), i);
                 }
                 field.Value = array;
             }
             else if (field.DataType.Name.StartsWith("List") && field.DataType.GenericTypeArguments.Length == 1)
             {
                 var   listType            = typeof(List <>);
                 var   constructedListType = listType.MakeGenericType(fieldType);
                 IList array = Activator.CreateInstance(constructedListType) as IList;
                 for (int i = 0; i < matches.Count; i++)
                 {
                     array.Add(GetModel(matches[i]));
                 }
                 field.Value = array;
             }
             else if (matches.Count == 0)
             {
                 if (!link.IsOptional)
                 {
                     throw new Exception("Cannot find a match for link " + field.Name + " in model " + GetFullName(obj));
                 }
             }
             else if (matches.Count >= 2 && !link.IsScoped(field))
             {
                 throw new Exception(string.Format(": Found {0} matches for link {1} in model {2} !", matches.Count, field.Name, GetFullName(obj)));
             }
             else
             {
                 field.Value = GetModel(matches[0]);
             }
         }
     }
 }
Exemplo n.º 2
0
        /// <summary>
        /// Internal [link] resolution algorithm.
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="allModels">A collection of all model wrappers</param>
        private void ResolveInternal(object obj, List <ModelWrapper> allModels)
        {
            // Go looking for [Link]s
            foreach (FieldInfo field in ReflectionUtilities.GetAllFields(
                         GetModel(obj).GetType(),
                         BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.NonPublic | BindingFlags.Public))
            {
                LinkAttribute link = GetLinkAttribute(field);

                if (link != null)
                {
                    // Get the field type or the array element if it is an array field.
                    Type fieldType = field.FieldType;
                    if (fieldType.IsArray)
                    {
                        fieldType = fieldType.GetElementType();
                    }
                    else if (field.FieldType.Name.StartsWith("List") && field.FieldType.GenericTypeArguments.Length == 1)
                    {
                        fieldType = field.FieldType.GenericTypeArguments[0];
                    }

                    // Try and get a match from our services first.
                    List <object> matches;
                    matches = services.FindAll(s => fieldType.IsAssignableFrom(s.GetType()));

                    // If no match on services then try other options.
                    if (matches.Count == 0 && obj is IModel)
                    {
                        Simulation parentSimulation = Apsim.Parent(obj as IModel, typeof(Simulation)) as Simulation;
                        if (fieldType.IsAssignableFrom(typeof(ILocator)) && parentSimulation != null)
                        {
                            matches.Add(new Locator(obj as IModel));
                        }
                        else if (fieldType.IsAssignableFrom(typeof(IEvent)) && parentSimulation != null)
                        {
                            matches.Add(new Events(obj as IModel));
                        }
                    }

                    // If no match on services then try other options.
                    if (matches.Count == 0)
                    {
                        // Get a list of models that could possibly match.
                        if (link is ParentLinkAttribute)
                        {
                            matches = new List <object>();
                            matches.Add(GetParent(obj, fieldType));
                        }
                        else if (link.IsScoped(field))
                        {
                            matches = GetModelsInScope(obj, allModels);
                        }
                        else
                        {
                            matches = GetChildren(obj);
                        }
                    }

                    // Filter possible matches to those of the correct type.
                    matches.RemoveAll(match => !fieldType.IsAssignableFrom(GetModel(match).GetType()));

                    // If we should use name to match then filter matches to those with a matching name.
                    if (link.UseNameToMatch(field))
                    {
                        matches.RemoveAll(match => !StringUtilities.StringsAreEqual(GetName(match), field.Name));
                    }

                    if (field.FieldType.IsArray)
                    {
                        Array array = Array.CreateInstance(fieldType, matches.Count);
                        for (int i = 0; i < matches.Count; i++)
                        {
                            array.SetValue(GetModel(matches[i]), i);
                        }
                        field.SetValue(GetModel(obj), array);
                    }
                    else if (field.FieldType.Name.StartsWith("List") && field.FieldType.GenericTypeArguments.Length == 1)
                    {
                        var   listType            = typeof(List <>);
                        var   constructedListType = listType.MakeGenericType(fieldType);
                        IList array = Activator.CreateInstance(constructedListType) as IList;
                        for (int i = 0; i < matches.Count; i++)
                        {
                            array.Add(GetModel(matches[i]));
                        }
                        field.SetValue(GetModel(obj), array);
                    }
                    else if (matches.Count == 0)
                    {
                        if (!link.IsOptional)
                        {
                            throw new Exception("Cannot find a match for link " + field.Name + " in model " + GetFullName(obj));
                        }
                    }
                    else if (matches.Count >= 2 && !link.IsScoped(field))
                    {
                        throw new Exception(string.Format(": Found {0} matches for link {1} in model {2} !", matches.Count, field.Name, GetFullName(obj)));
                    }
                    else
                    {
                        field.SetValue(GetModel(obj), GetModel(matches[0]));
                    }
                }
            }
        }