123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239 |
- // Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy of this
- // software and associated documentation files (the "Software"), to deal in the Software
- // without restriction, including without limitation the rights to use, copy, modify, merge,
- // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
- // to whom the Software is furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in all copies or
- // substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
- // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
- // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- // DEALINGS IN THE SOFTWARE.
- using System;
- using System.Collections.Concurrent;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.Collections.Specialized;
- using System.IO;
- using System.Linq;
- //using System.Windows.Threading;
- using System.Xml.Linq;
- namespace ICSharpCode.ILSpy
- {
- /// <summary>
- /// A list of assemblies.
- /// </summary>
- public class AssemblyList
- {
- readonly string listName;
-
- /// <summary>Dirty flag, used to mark modifications so that the list is saved later</summary>
- bool dirty;
-
- internal readonly ConcurrentDictionary<string, LoadedAssembly> assemblyLookupCache = new ConcurrentDictionary<string, LoadedAssembly>();
- internal readonly ConcurrentDictionary<string, LoadedAssembly> winRTMetadataLookupCache = new ConcurrentDictionary<string, LoadedAssembly>();
-
- /// <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>
- /// <remarks>
- /// Technically read accesses need locking when done on non-GUI threads... but whenever possible, use the
- /// thread-safe <see cref="GetAssemblies()"/> method.
- /// </remarks>
- internal readonly List<LoadedAssembly> assemblies = new List<LoadedAssembly>();
-
- public AssemblyList(string listName)
- {
- this.listName = listName;
- // assemblies.CollectionChanged += Assemblies_CollectionChanged;
- }
-
- /// <summary>
- /// Loads an assembly list from XML.
- /// </summary>
- public AssemblyList(XElement listElement)
- : this((string)listElement.Attribute("name"))
- {
- foreach (var asm in listElement.Elements("Assembly")) {
- OpenAssembly((string)asm);
- }
- this.dirty = false; // OpenAssembly() sets dirty, so reset it afterwards
- }
-
- /// <summary>
- /// Gets the loaded assemblies. This method is thread-safe.
- /// </summary>
- public LoadedAssembly[] GetAssemblies()
- {
- lock (assemblies) {
- return assemblies.ToArray();
- }
- }
-
- /// <summary>
- /// Saves this assembly list to XML.
- /// </summary>
- internal XElement SaveAsXml()
- {
- return new XElement(
- "List",
- new XAttribute("name", this.ListName),
- assemblies.Where(asm => !asm.IsAutoLoaded).Select(asm => new XElement("Assembly", asm.FileName))
- );
- }
- public LoadedAssembly findAssemblyByShortName (string shortName)
- {
- foreach (LoadedAssembly asm in assemblies) {
- if (asm.ShortName == shortName) {
- return asm;
- }
- }
- return null;
- }
-
- /// <summary>
- /// Gets the name of this list.
- /// </summary>
- public string ListName {
- get { return listName; }
- }
-
- void Assemblies_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
- {
- ClearCache();
- // Whenever the assembly list is modified, mark it as dirty
- // and enqueue a task that saves it once the UI has finished modifying the assembly list.
- if (!dirty) {
- dirty = true;
- // App.Current.Dispatcher.BeginInvoke(
- // DispatcherPriority.Background,
- // new Action(
- // delegate {
- // dirty = false;
- // AssemblyListManager.SaveList(this);
- // ClearCache();
- // })
- // );
- }
- }
- internal void RefreshSave()
- {
- if (!dirty) {
- dirty = true;
- // App.Current.Dispatcher.BeginInvoke(
- // DispatcherPriority.Background,
- // new Action(
- // delegate {
- // dirty = false;
- // AssemblyListManager.SaveList(this);
- // })
- // );
- }
- }
-
- internal void ClearCache()
- {
- assemblyLookupCache.Clear();
- winRTMetadataLookupCache.Clear();
- }
-
- /// <summary>
- /// Opens an assembly from disk.
- /// Returns the existing assembly node if it is already loaded.
- /// </summary>
- public LoadedAssembly OpenAssembly(string file, bool isAutoLoaded=false)
- {
- //App.Current.Dispatcher.VerifyAccess();
-
- file = Path.GetFullPath(file);
-
- foreach (LoadedAssembly asm in this.assemblies) {
- if (file.Equals(asm.FileName, StringComparison.OrdinalIgnoreCase))
- return asm;
- }
-
- var newAsm = new LoadedAssembly(this, file);
- newAsm.IsAutoLoaded = isAutoLoaded;
- lock (assemblies) {
- this.assemblies.Add(newAsm);
- }
- return newAsm;
- }
- /// <summary>
- /// Replace the assembly object model from a crafted stream, without disk I/O
- /// Returns null if it is not already loaded.
- /// </summary>
- // public LoadedAssembly HotReplaceAssembly(string file, Stream stream)
- // {
- // App.Current.Dispatcher.VerifyAccess();
- // file = Path.GetFullPath(file);
- //
- // var target = this.assemblies.FirstOrDefault(asm => file.Equals(asm.FileName, StringComparison.OrdinalIgnoreCase));
- // if (target == null)
- // return null;
- //
- // var index = this.assemblies.IndexOf(target);
- // var newAsm = new LoadedAssembly(this, file, stream);
- // newAsm.IsAutoLoaded = target.IsAutoLoaded;
- // lock (assemblies)
- // {
- // this.assemblies.Remove(target);
- // this.assemblies.Insert(index, newAsm);
- // }
- // return newAsm;
- // }
-
- public void Unload(LoadedAssembly assembly)
- {
- //App.Current.Dispatcher.VerifyAccess();
- lock (assemblies) {
- assemblies.Remove(assembly);
- }
- RequestGC();
- }
-
- static bool gcRequested;
-
- void RequestGC()
- {
- if (gcRequested) return;
- gcRequested = true;
- // App.Current.Dispatcher.BeginInvoke(DispatcherPriority.ContextIdle, new Action(
- // delegate {
- // gcRequested = false;
- // GC.Collect();
- // }));
- }
-
- public void Sort(IComparer<LoadedAssembly> comparer)
- {
- Sort(0, int.MaxValue, comparer);
- }
-
- public void Sort(int index, int count, IComparer<LoadedAssembly> comparer)
- {
- //App.Current.Dispatcher.VerifyAccess();
- lock (assemblies) {
- List<LoadedAssembly> list = new List<LoadedAssembly>(assemblies);
- list.Sort(index, Math.Min(count, list.Count - index), comparer);
- assemblies.Clear();
- assemblies.AddRange(list);
- }
- }
- }
- }
|