Browse Source

Fix threading issues when accessing AssemblyList.Assemblies.

pull/10/head
Daniel Grunwald 14 years ago
parent
commit
a44673a170
  1. 22
      ILSpy/AssemblyList.cs
  2. 4
      ILSpy/MainWindow.xaml.cs
  3. 2
      ILSpy/TextView/DecompilerTextView.cs
  4. 34
      ILSpy/TreeNodes/AssemblyListTreeNode.cs
  5. 33
      ILSpy/TreeNodes/AssemblyTreeNode.cs
  6. 2
      ILSpy/TreeNodes/DerivedTypesTreeNode.cs

22
ILSpy/AssemblyList.cs

@ -41,8 +41,10 @@ namespace ICSharpCode.ILSpy @@ -41,8 +41,10 @@ namespace ICSharpCode.ILSpy
/// <summary>
/// The assemblies in this list.
/// Needs locking for multi-threaded access!
/// Write accesses are allowed on the GUI thread only (but still need locking!)
/// </summary>
public readonly ObservableCollection<AssemblyTreeNode> Assemblies = new ObservableCollection<AssemblyTreeNode>();
internal readonly ObservableCollection<AssemblyTreeNode> assemblies = new ObservableCollection<AssemblyTreeNode>();
/// <summary>
/// Dictionary for quickly finding types (used in hyperlink navigation)
@ -52,7 +54,7 @@ namespace ICSharpCode.ILSpy @@ -52,7 +54,7 @@ namespace ICSharpCode.ILSpy
public AssemblyList(string listName)
{
this.listName = listName;
Assemblies.CollectionChanged += Assemblies_CollectionChanged;
assemblies.CollectionChanged += Assemblies_CollectionChanged;
}
/// <summary>
@ -67,6 +69,16 @@ namespace ICSharpCode.ILSpy @@ -67,6 +69,16 @@ namespace ICSharpCode.ILSpy
this.dirty = false; // OpenAssembly() sets dirty, so reset it afterwards
}
/// <summary>
/// Gets the loaded assemblies. This method is thread-safe.
/// </summary>
public AssemblyTreeNode[] GetAssemblies()
{
lock (assemblies) {
return assemblies.ToArray();
}
}
/// <summary>
/// Saves this assembly list to XML.
/// </summary>
@ -75,7 +87,7 @@ namespace ICSharpCode.ILSpy @@ -75,7 +87,7 @@ namespace ICSharpCode.ILSpy
return new XElement(
"List",
new XAttribute("name", this.ListName),
Assemblies.Select(asm => new XElement("Assembly", asm.FileName))
assemblies.Select(asm => new XElement("Assembly", asm.FileName))
);
}
@ -215,13 +227,13 @@ namespace ICSharpCode.ILSpy @@ -215,13 +227,13 @@ namespace ICSharpCode.ILSpy
file = Path.GetFullPath(file);
foreach (AssemblyTreeNode node in this.Assemblies) {
foreach (AssemblyTreeNode node in this.assemblies) {
if (file.Equals(node.FileName, StringComparison.OrdinalIgnoreCase))
return node;
}
var newNode = new AssemblyTreeNode(file, this);
this.Assemblies.Add(newNode);
this.assemblies.Add(newNode);
return newNode;
}
}

4
ILSpy/MainWindow.xaml.cs

@ -93,7 +93,7 @@ namespace ICSharpCode.ILSpy @@ -93,7 +93,7 @@ namespace ICSharpCode.ILSpy
for (int i = 1; i < args.Length; i++) {
assemblyList.OpenAssembly(args[i]);
}
if (assemblyList.Assemblies.Count == 0)
if (assemblyList.GetAssemblies().Length == 0)
LoadInitialAssemblies();
SharpTreeNode node = FindNodeByPath(sessionSettings.ActiveTreeViewPath, true);
@ -139,7 +139,7 @@ namespace ICSharpCode.ILSpy @@ -139,7 +139,7 @@ namespace ICSharpCode.ILSpy
history.Clear();
this.assemblyList = assemblyList;
assemblyList.Assemblies.CollectionChanged += assemblyList_Assemblies_CollectionChanged;
assemblyList.assemblies.CollectionChanged += assemblyList_Assemblies_CollectionChanged;
assemblyListTreeNode = new AssemblyListTreeNode(assemblyList);
assemblyListTreeNode.FilterSettings = sessionSettings.FilterSettings.Clone();

2
ILSpy/TextView/DecompilerTextView.cs

@ -358,7 +358,7 @@ namespace ICSharpCode.ILSpy.TextView @@ -358,7 +358,7 @@ namespace ICSharpCode.ILSpy.TextView
} else if (reference is EventReference) {
mainWindow.SelectNode(assemblyList.FindEventNode(((EventReference)reference).Resolve()));
} else if (reference is AssemblyDefinition) {
mainWindow.SelectNode(assemblyList.Assemblies.FirstOrDefault(node => node.AssemblyDefinition == reference));
mainWindow.SelectNode(assemblyList.GetAssemblies().FirstOrDefault(node => node.AssemblyDefinition == reference));
}
}
#endregion

34
ILSpy/TreeNodes/AssemblyListTreeNode.cs

@ -38,7 +38,7 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -38,7 +38,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
}
public AssemblyListTreeNode(AssemblyList assemblyList)
: base(assemblyList.Assemblies)
: base(assemblyList.assemblies)
{
if (assemblyList == null)
throw new ArgumentNullException("assemblyList");
@ -61,20 +61,22 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -61,20 +61,22 @@ namespace ICSharpCode.ILSpy.TreeNodes
if (files == null)
files = data.GetData(DataFormats.FileDrop) as string[];
if (files != null) {
var nodes = (from file in files
where file != null
select assemblyList.OpenAssembly(file) into node
where node != null
select node).Distinct().ToList();
foreach (AssemblyTreeNode node in nodes) {
int nodeIndex = this.Children.IndexOf(node);
if (nodeIndex < index)
index--;
this.Children.RemoveAt(nodeIndex);
}
nodes.Reverse();
foreach (AssemblyTreeNode node in nodes) {
this.Children.Insert(index, node);
lock (assemblyList.assemblies) {
var nodes = (from file in files
where file != null
select assemblyList.OpenAssembly(file) into node
where node != null
select node).Distinct().ToList();
foreach (AssemblyTreeNode node in nodes) {
int nodeIndex = assemblyList.assemblies.IndexOf(node);
if (nodeIndex < index)
index--;
assemblyList.assemblies.RemoveAt(nodeIndex);
}
nodes.Reverse();
foreach (AssemblyTreeNode node in nodes) {
assemblyList.assemblies.Insert(index, node);
}
}
}
}
@ -85,7 +87,7 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -85,7 +87,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
{
language.WriteCommentLine(output, "List: " + assemblyList.ListName);
output.WriteLine();
foreach (AssemblyTreeNode asm in assemblyList.Assemblies) {
foreach (AssemblyTreeNode asm in assemblyList.GetAssemblies()) {
language.WriteCommentLine(output, new string('-', 60));
output.WriteLine();
asm.Decompile(language, output, options);

33
ILSpy/TreeNodes/AssemblyTreeNode.cs

@ -25,7 +25,7 @@ using System.Threading; @@ -25,7 +25,7 @@ using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using ICSharpCode.Decompiler;
using ICSharpCode.TreeView;
using Mono.Cecil;
@ -128,18 +128,6 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -128,18 +128,6 @@ namespace ICSharpCode.ILSpy.TreeNodes
}
}
MenuItem CreateRemoveAssemblyItem()
{
MenuItem item = new MenuItem() {
Header = "Remove assembly",
Icon = new Image() { Source = Images.Delete }
};
item.Click += delegate { Delete(); };
return item;
}
sealed class MyAssemblyResolver : IAssemblyResolver
{
readonly AssemblyTreeNode parent;
@ -178,7 +166,13 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -178,7 +166,13 @@ namespace ICSharpCode.ILSpy.TreeNodes
{
// specific to AssemblyTreeNode
var menu = new ContextMenu();
menu.Items.Add(CreateRemoveAssemblyItem());
MenuItem item = new MenuItem() {
Header = "Remove assembly",
Icon = new Image() { Source = Images.Delete }
};
item.Click += delegate { Delete(); };
menu.Items.Add(item);
return menu;
}
@ -229,7 +223,9 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -229,7 +223,9 @@ namespace ICSharpCode.ILSpy.TreeNodes
public override void DeleteCore()
{
assemblyList.Assemblies.Remove(this);
lock (assemblyList.assemblies) {
assemblyList.assemblies.Remove(this);
}
}
internal const string DataFormat = "ILSpyAssemblies";
@ -243,11 +239,16 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -243,11 +239,16 @@ namespace ICSharpCode.ILSpy.TreeNodes
public AssemblyTreeNode LookupReferencedAssembly(string fullName)
{
foreach (AssemblyTreeNode node in assemblyList.Assemblies) {
foreach (AssemblyTreeNode node in assemblyList.GetAssemblies()) {
if (node.AssemblyDefinition != null && fullName.Equals(node.AssemblyDefinition.FullName, StringComparison.OrdinalIgnoreCase))
return node;
}
if (!App.Current.Dispatcher.CheckAccess()) {
// Call this method on the GUI thread.
return (AssemblyTreeNode)App.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Func<string, AssemblyTreeNode>(LookupReferencedAssembly), fullName);
}
var name = AssemblyNameReference.Parse(fullName);
string file = GacInterop.FindAssemblyInNetGac(name);
if (file == null) {

2
ILSpy/TreeNodes/DerivedTypesTreeNode.cs

@ -37,7 +37,7 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -37,7 +37,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
protected override IEnumerable<ILSpyTreeNodeBase> FetchChildren(CancellationToken cancellationToken)
{
// FetchChildren() runs on the main thread; but the enumerator will be consumed on a background thread
var assemblies = list.Assemblies.Select(node => node.AssemblyDefinition).Where(asm => asm != null).ToArray();
var assemblies = list.GetAssemblies().Select(node => node.AssemblyDefinition).Where(asm => asm != null).ToArray();
return FindDerivedTypes(type, assemblies, cancellationToken);
}

Loading…
Cancel
Save