AssemblyList.cs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. // Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy of this
  4. // software and associated documentation files (the "Software"), to deal in the Software
  5. // without restriction, including without limitation the rights to use, copy, modify, merge,
  6. // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
  7. // to whom the Software is furnished to do so, subject to the following conditions:
  8. //
  9. // The above copyright notice and this permission notice shall be included in all copies or
  10. // substantial portions of the Software.
  11. //
  12. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  13. // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  14. // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
  15. // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  16. // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  17. // DEALINGS IN THE SOFTWARE.
  18. using System;
  19. using System.Collections.Concurrent;
  20. using System.Collections.Generic;
  21. using System.Collections.ObjectModel;
  22. using System.Collections.Specialized;
  23. using System.IO;
  24. using System.Linq;
  25. //using System.Windows.Threading;
  26. using System.Xml.Linq;
  27. namespace ICSharpCode.ILSpy
  28. {
  29. /// <summary>
  30. /// A list of assemblies.
  31. /// </summary>
  32. public class AssemblyList
  33. {
  34. readonly string listName;
  35. /// <summary>Dirty flag, used to mark modifications so that the list is saved later</summary>
  36. bool dirty;
  37. internal readonly ConcurrentDictionary<string, LoadedAssembly> assemblyLookupCache = new ConcurrentDictionary<string, LoadedAssembly>();
  38. internal readonly ConcurrentDictionary<string, LoadedAssembly> winRTMetadataLookupCache = new ConcurrentDictionary<string, LoadedAssembly>();
  39. /// <summary>
  40. /// The assemblies in this list.
  41. /// Needs locking for multi-threaded access!
  42. /// Write accesses are allowed on the GUI thread only (but still need locking!)
  43. /// </summary>
  44. /// <remarks>
  45. /// Technically read accesses need locking when done on non-GUI threads... but whenever possible, use the
  46. /// thread-safe <see cref="GetAssemblies()"/> method.
  47. /// </remarks>
  48. internal readonly List<LoadedAssembly> assemblies = new List<LoadedAssembly>();
  49. public AssemblyList(string listName)
  50. {
  51. this.listName = listName;
  52. // assemblies.CollectionChanged += Assemblies_CollectionChanged;
  53. }
  54. /// <summary>
  55. /// Loads an assembly list from XML.
  56. /// </summary>
  57. public AssemblyList(XElement listElement)
  58. : this((string)listElement.Attribute("name"))
  59. {
  60. foreach (var asm in listElement.Elements("Assembly")) {
  61. OpenAssembly((string)asm);
  62. }
  63. this.dirty = false; // OpenAssembly() sets dirty, so reset it afterwards
  64. }
  65. /// <summary>
  66. /// Gets the loaded assemblies. This method is thread-safe.
  67. /// </summary>
  68. public LoadedAssembly[] GetAssemblies()
  69. {
  70. lock (assemblies) {
  71. return assemblies.ToArray();
  72. }
  73. }
  74. /// <summary>
  75. /// Saves this assembly list to XML.
  76. /// </summary>
  77. internal XElement SaveAsXml()
  78. {
  79. return new XElement(
  80. "List",
  81. new XAttribute("name", this.ListName),
  82. assemblies.Where(asm => !asm.IsAutoLoaded).Select(asm => new XElement("Assembly", asm.FileName))
  83. );
  84. }
  85. public LoadedAssembly findAssemblyByShortName (string shortName)
  86. {
  87. foreach (LoadedAssembly asm in assemblies) {
  88. if (asm.ShortName == shortName) {
  89. return asm;
  90. }
  91. }
  92. return null;
  93. }
  94. /// <summary>
  95. /// Gets the name of this list.
  96. /// </summary>
  97. public string ListName {
  98. get { return listName; }
  99. }
  100. void Assemblies_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
  101. {
  102. ClearCache();
  103. // Whenever the assembly list is modified, mark it as dirty
  104. // and enqueue a task that saves it once the UI has finished modifying the assembly list.
  105. if (!dirty) {
  106. dirty = true;
  107. // App.Current.Dispatcher.BeginInvoke(
  108. // DispatcherPriority.Background,
  109. // new Action(
  110. // delegate {
  111. // dirty = false;
  112. // AssemblyListManager.SaveList(this);
  113. // ClearCache();
  114. // })
  115. // );
  116. }
  117. }
  118. internal void RefreshSave()
  119. {
  120. if (!dirty) {
  121. dirty = true;
  122. // App.Current.Dispatcher.BeginInvoke(
  123. // DispatcherPriority.Background,
  124. // new Action(
  125. // delegate {
  126. // dirty = false;
  127. // AssemblyListManager.SaveList(this);
  128. // })
  129. // );
  130. }
  131. }
  132. internal void ClearCache()
  133. {
  134. assemblyLookupCache.Clear();
  135. winRTMetadataLookupCache.Clear();
  136. }
  137. /// <summary>
  138. /// Opens an assembly from disk.
  139. /// Returns the existing assembly node if it is already loaded.
  140. /// </summary>
  141. public LoadedAssembly OpenAssembly(string file, bool isAutoLoaded=false)
  142. {
  143. //App.Current.Dispatcher.VerifyAccess();
  144. file = Path.GetFullPath(file);
  145. foreach (LoadedAssembly asm in this.assemblies) {
  146. if (file.Equals(asm.FileName, StringComparison.OrdinalIgnoreCase))
  147. return asm;
  148. }
  149. var newAsm = new LoadedAssembly(this, file);
  150. newAsm.IsAutoLoaded = isAutoLoaded;
  151. lock (assemblies) {
  152. this.assemblies.Add(newAsm);
  153. }
  154. return newAsm;
  155. }
  156. /// <summary>
  157. /// Replace the assembly object model from a crafted stream, without disk I/O
  158. /// Returns null if it is not already loaded.
  159. /// </summary>
  160. // public LoadedAssembly HotReplaceAssembly(string file, Stream stream)
  161. // {
  162. // App.Current.Dispatcher.VerifyAccess();
  163. // file = Path.GetFullPath(file);
  164. //
  165. // var target = this.assemblies.FirstOrDefault(asm => file.Equals(asm.FileName, StringComparison.OrdinalIgnoreCase));
  166. // if (target == null)
  167. // return null;
  168. //
  169. // var index = this.assemblies.IndexOf(target);
  170. // var newAsm = new LoadedAssembly(this, file, stream);
  171. // newAsm.IsAutoLoaded = target.IsAutoLoaded;
  172. // lock (assemblies)
  173. // {
  174. // this.assemblies.Remove(target);
  175. // this.assemblies.Insert(index, newAsm);
  176. // }
  177. // return newAsm;
  178. // }
  179. public void Unload(LoadedAssembly assembly)
  180. {
  181. //App.Current.Dispatcher.VerifyAccess();
  182. lock (assemblies) {
  183. assemblies.Remove(assembly);
  184. }
  185. RequestGC();
  186. }
  187. static bool gcRequested;
  188. void RequestGC()
  189. {
  190. if (gcRequested) return;
  191. gcRequested = true;
  192. // App.Current.Dispatcher.BeginInvoke(DispatcherPriority.ContextIdle, new Action(
  193. // delegate {
  194. // gcRequested = false;
  195. // GC.Collect();
  196. // }));
  197. }
  198. public void Sort(IComparer<LoadedAssembly> comparer)
  199. {
  200. Sort(0, int.MaxValue, comparer);
  201. }
  202. public void Sort(int index, int count, IComparer<LoadedAssembly> comparer)
  203. {
  204. //App.Current.Dispatcher.VerifyAccess();
  205. lock (assemblies) {
  206. List<LoadedAssembly> list = new List<LoadedAssembly>(assemblies);
  207. list.Sort(index, Math.Min(count, list.Count - index), comparer);
  208. assemblies.Clear();
  209. assemblies.AddRange(list);
  210. }
  211. }
  212. }
  213. }