public void OnFindReferences(object sender, EventArgs e) { try { IModel model = Apsim.Get(this.explorerPresenter.ApsimXFile, this.explorerPresenter.CurrentNodePath) as IModel; if (model != null) { string modelPath = Apsim.FullPath(model); StringBuilder message = new StringBuilder($"Searching for references to model {Apsim.FullPath(model)}..."); List <Reference> references = new List <Reference>(); message.AppendLine(); message.AppendLine(); Stopwatch timer = Stopwatch.StartNew(); foreach (VariableReference reference in Apsim.FindAll(model, typeof(VariableReference))) { try { if (Apsim.Get(reference, reference.VariableName.Replace(".Value()", "")) == model) { references.Add(new Reference() { Member = typeof(VariableReference).GetProperty("VariableName"), Model = reference, Target = model }); } } catch { } } timer.Stop(); message.AppendLine(); message.AppendLine($"Finished. Elapsed time: {timer.Elapsed.TotalSeconds.ToString("#.00")} seconds"); explorerPresenter.MainPresenter.ShowMessage(message.ToString(), Simulation.MessageType.Information); var dialog = new Utility.FindAllReferencesDialog(model, references, explorerPresenter); } } catch (Exception err) { explorerPresenter.MainPresenter.ShowError(err); } }
public void OnFindReferences(object sender, EventArgs e) { try { IModel model = Apsim.Get(this.explorerPresenter.ApsimXFile, this.explorerPresenter.CurrentNodePath) as IModel; if (model != null) { string modelPath = Apsim.FullPath(model); StringBuilder message = new StringBuilder($"Searching for references to model {Apsim.FullPath(model)}..."); List <Reference> references = new List <Reference>(); message.AppendLine(); message.AppendLine(); Stopwatch timer = Stopwatch.StartNew(); BindingFlags flags; foreach (IModel child in Apsim.FindAll(model)) { if (Apsim.FullPath(child) == Apsim.FullPath(model)) { continue; } // Resolve links (this doesn't seem to work properly). explorerPresenter.ApsimXFile.Links.Resolve(child, throwOnFail: false); MemberInfo[] members = null; Type childType = child.GetType(); // First, find all links to the model. // First, try the cache. if (!links.TryGetValue(childType, out members)) { // We haven't looked for members of this type before. List <MemberInfo> localMembers = new List <MemberInfo>(); // Links may be static or non-static (instance), and can have any accessibility. flags = BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; // Find all properties which are links. localMembers.AddRange(child.GetType().GetProperties(flags).Where(p => ReflectionUtilities.GetAttribute(p, typeof(LinkAttribute), true) != null)); // Find all fields which are links. localMembers.AddRange(child.GetType().GetFields(flags).Where(f => ReflectionUtilities.GetAttribute(f, typeof(LinkAttribute), true) != null)); members = localMembers.ToArray(); // Add members to cache. links.Add(childType, members); } // Now iterate over all members of this type which are links. foreach (MemberInfo member in members) { IModel linkValue = ReflectionUtilities.GetValueOfFieldOrProperty(member.Name, child) as IModel; if (linkValue == null) { continue; // Silently ignore this member. } bool isCorrectType = model.GetType().IsAssignableFrom(linkValue.GetType()); bool hasCorrectPath = string.Equals(Apsim.FullPath(linkValue), modelPath, StringComparison.InvariantCulture); if (isCorrectType && hasCorrectPath) { message.AppendLine($"Found member {member.Name} of node {Apsim.FullPath(child)}."); references.Add(new Reference() { Member = member, Target = model, Model = child }); } } //if (model is IFunction && child is IFunction) { // Next, search all public string properties for the path to this model. PropertyInfo[] properties; if (!stringProperties.TryGetValue(childType, out properties)) { flags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public; properties = childType.GetProperties(flags).Where(p => p.PropertyType == typeof(string) && p.CanRead).ToArray(); stringProperties.Add(childType, properties); } foreach (PropertyInfo property in properties) { string value; try { // An exception could be thrown here from inside the property's getter. value = property.GetValue(child) as string; } catch { continue; } if (value == null) { continue; } value = value.Replace(".Value()", "").Replace(".Value", ""); IModel result = null; try { result = Apsim.Get(child, value) as IModel; } catch { continue; } if (result == null) { continue; } bool correctType = model.GetType().IsAssignableFrom(result.GetType()); bool correctPath = string.Equals(Apsim.FullPath(result), modelPath, StringComparison.InvariantCulture); if (correctType && correctPath) { message.AppendLine($"Found reference in string property {property.Name} of node {Apsim.FullPath(child)}."); references.Add(new Reference() { Member = property, Target = model, Model = child }); } } } } timer.Stop(); message.AppendLine(); message.AppendLine($"Finished. Elapsed time: {timer.Elapsed.TotalSeconds.ToString("#.00")} seconds"); explorerPresenter.MainPresenter.ShowMessage(message.ToString(), Simulation.MessageType.Information); var dialog = new Utility.FindAllReferencesDialog(model, references, explorerPresenter); } } catch (Exception err) { explorerPresenter.MainPresenter.ShowError(err); } }