From 560d89a42fdad2b1b91f357a77562f919166649a Mon Sep 17 00:00:00 2001 From: tom-englert Date: Sat, 26 Oct 2024 10:48:27 +0200 Subject: [PATCH 1/4] Get rid of singletons, replace with DI: MainWindow, Settings and Language service --- ILSpy.ReadyToRun/ReadyToRunDisassembler.cs | 6 +- ILSpy.ReadyToRun/ReadyToRunLanguage.cs | 12 ++-- .../MemberImplementsInterfaceAnalyzerTests.cs | 2 +- .../Analyzers/MethodUsesAnalyzerTests.cs | 2 +- .../Analyzers/TypeUsedByAnalyzerTests.cs | 2 +- ILSpy/AboutPage.cs | 15 +++-- ILSpy/Analyzers/AnalyzeCommand.cs | 21 +++--- ILSpy/Analyzers/AnalyzerSearchTreeNode.cs | 2 +- ILSpy/Analyzers/AnalyzerTreeNode.cs | 14 +++- ILSpy/Analyzers/AnalyzerTreeViewModel.cs | 5 +- .../TreeNodes/AnalyzedEventTreeNode.cs | 15 ++--- .../TreeNodes/AnalyzedFieldTreeNode.cs | 7 +- .../TreeNodes/AnalyzedMethodTreeNode.cs | 5 +- .../TreeNodes/AnalyzedModuleTreeNode.cs | 5 +- .../TreeNodes/AnalyzedPropertyTreeNode.cs | 7 +- .../TreeNodes/AnalyzedTypeTreeNode.cs | 5 +- ILSpy/App.xaml.cs | 16 +++-- ILSpy/AssemblyTree/AssemblyTreeModel.cs | 53 ++++++++------- ILSpy/Commands/CheckForUpdatesCommand.cs | 9 +-- ILSpy/Commands/DecompileAllCommand.cs | 25 +++----- ILSpy/Commands/DisassembleAllCommand.cs | 8 ++- ILSpy/Commands/ExitCommand.cs | 2 +- ILSpy/Commands/GeneratePdbContextMenuEntry.cs | 20 +++--- ILSpy/Commands/ILSpyCommands.cs | 37 ----------- ILSpy/Commands/ManageAssemblyListsCommand.cs | 6 +- ILSpy/Commands/OpenFromGacCommand.cs | 2 +- ILSpy/Commands/Pdb2XmlCommand.cs | 7 +- .../RemoveAssembliesWithLoadErrors.cs | 11 +--- ILSpy/Commands/SaveCodeContextMenuEntry.cs | 11 ++-- ILSpy/Commands/SaveCommand.cs | 12 +--- ILSpy/Commands/SelectPdbContextMenuEntry.cs | 9 +-- ILSpy/Commands/SetThemeCommand.cs | 8 ++- ILSpy/Commands/SortAssemblyListCommand.cs | 9 +-- ILSpy/ContextMenuEntry.cs | 3 +- ILSpy/Docking/DockWorkspace.cs | 36 ++++++----- ILSpy/ExtensionMethods.cs | 7 +- ILSpy/Languages/CSharpILMixedLanguage.cs | 4 +- ILSpy/Languages/CSharpLanguage.cs | 38 +++++------ ILSpy/Languages/ILLanguage.cs | 6 +- ILSpy/Languages/Language.cs | 8 +++ ILSpy/Languages/LanguageService.cs | 18 ++---- ILSpy/MainWindow.xaml | 10 +-- ILSpy/MainWindow.xaml.cs | 59 ++++++++--------- ILSpy/MainWindowViewModel.cs | 16 +++-- .../Metadata/CorTables/EventTableTreeNode.cs | 2 +- .../Metadata/CorTables/FieldTableTreeNode.cs | 2 +- .../Metadata/CorTables/MethodTableTreeNode.cs | 2 +- .../CorTables/PropertyTableTreeNode.cs | 2 +- .../CorTables/TypeDefTableTreeNode.cs | 2 +- ILSpy/Metadata/DebugMetadataTablesTreeNode.cs | 2 +- ILSpy/Metadata/MetadataProtocolHandler.cs | 5 +- ILSpy/Metadata/MetadataTablesTreeNode.cs | 2 +- ILSpy/Options/OptionsDialog.xaml.cs | 17 ++--- ILSpy/Options/OptionsDialogViewModel.cs | 4 +- ILSpy/Search/SearchPane.xaml.cs | 64 ++++++++++++------- ILSpy/Search/SearchPaneModel.cs | 9 ++- ILSpy/Search/SearchResultFactory.cs | 4 ++ ILSpy/SolutionWriter.cs | 3 +- ILSpy/TaskHelper.cs | 2 +- ILSpy/TextView/DecompilerTextView.cs | 60 +++++++++-------- ILSpy/TextView/DocumentationUIBuilder.cs | 13 ++-- ILSpy/Themes/WindowStyleManagerBehavior.cs | 32 ++++++---- ILSpy/TreeNodes/AssemblyListTreeNode.cs | 11 +++- ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs | 4 +- ILSpy/TreeNodes/AssemblyTreeNode.cs | 21 +++--- ILSpy/TreeNodes/DerivedTypesEntryNode.cs | 2 +- ILSpy/TreeNodes/EventTreeNode.cs | 6 +- ILSpy/TreeNodes/FieldTreeNode.cs | 6 +- ILSpy/TreeNodes/ILSpyTreeNode.cs | 28 +++++--- ILSpy/TreeNodes/MethodTreeNode.cs | 8 +-- ILSpy/TreeNodes/PropertyTreeNode.cs | 8 +-- ILSpy/TreeNodes/ReferenceFolderTreeNode.cs | 2 +- .../ResourceNodes/ResourceEntryNode.cs | 3 +- ILSpy/TreeNodes/TypeTreeNode.cs | 6 +- ILSpy/Util/MenuService.cs | 15 +++-- ILSpy/Util/SettingsService.cs | 9 +-- .../ManageAssemblyListsViewModel.cs | 18 +++--- ILSpy/ViewModels/TabPageModel.cs | 23 +++++-- ILSpy/Views/DebugSteps.xaml.cs | 20 ++++-- ILSpy/Views/ManageAssemblyLIstsDialog.xaml.cs | 4 +- TestPlugin/MainMenuCommand.cs | 5 +- 81 files changed, 521 insertions(+), 480 deletions(-) delete mode 100644 ILSpy/Commands/ILSpyCommands.cs diff --git a/ILSpy.ReadyToRun/ReadyToRunDisassembler.cs b/ILSpy.ReadyToRun/ReadyToRunDisassembler.cs index ce9e62a1e3..8d08b413eb 100644 --- a/ILSpy.ReadyToRun/ReadyToRunDisassembler.cs +++ b/ILSpy.ReadyToRun/ReadyToRunDisassembler.cs @@ -38,12 +38,14 @@ internal class ReadyToRunDisassembler private readonly ITextOutput output; private readonly ReadyToRunReader reader; private readonly RuntimeFunction runtimeFunction; + private readonly SettingsService settingsService; - public ReadyToRunDisassembler(ITextOutput output, ReadyToRunReader reader, RuntimeFunction runtimeFunction) + public ReadyToRunDisassembler(ITextOutput output, ReadyToRunReader reader, RuntimeFunction runtimeFunction, SettingsService settingsService) { this.output = output; this.reader = reader; this.runtimeFunction = runtimeFunction; + this.settingsService = settingsService; } public void Disassemble(PEFile currentFile, int bitness, ulong address, bool showMetadataTokens, bool showMetadataTokensInBase10) @@ -51,7 +53,7 @@ public void Disassemble(PEFile currentFile, int bitness, ulong address, bool sho ReadyToRunMethod readyToRunMethod = runtimeFunction.Method; WriteCommentLine(readyToRunMethod.SignatureString); - var options = SettingsService.Instance.GetSettings(); + var options = settingsService.GetSettings(); if (options.IsShowGCInfo) { diff --git a/ILSpy.ReadyToRun/ReadyToRunLanguage.cs b/ILSpy.ReadyToRun/ReadyToRunLanguage.cs index 78e4788616..26a3dc0dfc 100644 --- a/ILSpy.ReadyToRun/ReadyToRunLanguage.cs +++ b/ILSpy.ReadyToRun/ReadyToRunLanguage.cs @@ -38,6 +38,10 @@ using ILCompiler.Reflection.ReadyToRun; +using TomsToolbox.Composition; + +using MetadataReader = System.Reflection.Metadata.MetadataReader; + namespace ICSharpCode.ILSpy.ReadyToRun { #if STRESS @@ -97,7 +101,7 @@ public void WriteReference(IMember member, string text, bool isDefinition = fals [Export(typeof(Language))] [Shared] - internal class ReadyToRunLanguage : Language + internal class ReadyToRunLanguage(SettingsService settingsService, IExportProvider exportProvider) : Language { private static readonly ConditionalWeakTable readyToRunReaders = new ConditionalWeakTable(); @@ -175,7 +179,7 @@ public override void DecompileMethod(IMethod method, ITextOutput output, Decompi .GroupBy(m => m.MethodHandle) .ToDictionary(g => g.Key, g => g.ToArray()); } - var displaySettings = SettingsService.Instance.DisplaySettings; + var displaySettings = settingsService.DisplaySettings; bool showMetadataTokens = displaySettings.ShowMetadataTokens; bool showMetadataTokensInBase10 = displaySettings.ShowMetadataTokensInBase10; #if STRESS @@ -205,7 +209,7 @@ public override void DecompileMethod(IMethod method, ITextOutput output, Decompi file = ((IlSpyAssemblyMetadata)readyToRunMethod.ComponentReader).Module; } - new ReadyToRunDisassembler(output, disassemblingReader, runtimeFunction).Disassemble(file, bitness, (ulong)runtimeFunction.StartAddress, showMetadataTokens, showMetadataTokensInBase10); + new ReadyToRunDisassembler(output, disassemblingReader, runtimeFunction, settingsService).Disassemble(file, bitness, (ulong)runtimeFunction.StartAddress, showMetadataTokens, showMetadataTokensInBase10); } } } @@ -218,7 +222,7 @@ public override void DecompileMethod(IMethod method, ITextOutput output, Decompi public override RichText GetRichTextTooltip(IEntity entity) { - return LanguageService.Instance.ILLanguage.GetRichTextTooltip(entity); + return exportProvider.GetExportedValue().ILLanguage.GetRichTextTooltip(entity); } private ReadyToRunReaderCacheEntry GetReader(LoadedAssembly assembly, MetadataFile file) diff --git a/ILSpy.Tests/Analyzers/MemberImplementsInterfaceAnalyzerTests.cs b/ILSpy.Tests/Analyzers/MemberImplementsInterfaceAnalyzerTests.cs index 7b6f77c281..1149418e86 100644 --- a/ILSpy.Tests/Analyzers/MemberImplementsInterfaceAnalyzerTests.cs +++ b/ILSpy.Tests/Analyzers/MemberImplementsInterfaceAnalyzerTests.cs @@ -145,7 +145,7 @@ public void VerifyReturnsOnlyInterfaceMembers() var analyzer = new MemberImplementsInterfaceAnalyzer(); // Act - var results = analyzer.Analyze(symbol, new AnalyzerContext() { AssemblyList = new ILSpyX.AssemblyList(), Language = new CSharpLanguage([]) }); + var results = analyzer.Analyze(symbol, new AnalyzerContext() { AssemblyList = new ILSpyX.AssemblyList(), Language = new CSharpLanguage() }); // Assert Assert.That(results, Is.Not.Null); diff --git a/ILSpy.Tests/Analyzers/MethodUsesAnalyzerTests.cs b/ILSpy.Tests/Analyzers/MethodUsesAnalyzerTests.cs index 79bbbee7dc..033deaa1d1 100644 --- a/ILSpy.Tests/Analyzers/MethodUsesAnalyzerTests.cs +++ b/ILSpy.Tests/Analyzers/MethodUsesAnalyzerTests.cs @@ -30,7 +30,7 @@ public void Setup() testAssembly = assemblyList.OpenAssembly(typeof(MethodUsesAnalyzerTests).Assembly.Location); assemblyList.OpenAssembly(typeof(void).Assembly.Location); testAssemblyTypeSystem = testAssembly.GetTypeSystemOrNull(); - language = new CSharpLanguage([]); + language = new CSharpLanguage(); typeDefinition = testAssemblyTypeSystem.FindType(typeof(TestCases.Main.MainAssembly)).GetDefinition(); } diff --git a/ILSpy.Tests/Analyzers/TypeUsedByAnalyzerTests.cs b/ILSpy.Tests/Analyzers/TypeUsedByAnalyzerTests.cs index 2a47b84acc..972cb6fc7c 100644 --- a/ILSpy.Tests/Analyzers/TypeUsedByAnalyzerTests.cs +++ b/ILSpy.Tests/Analyzers/TypeUsedByAnalyzerTests.cs @@ -41,7 +41,7 @@ public void Setup() assemblyList = new AssemblyList(); testAssembly = assemblyList.OpenAssembly(typeof(MethodUsesAnalyzerTests).Assembly.Location); testAssemblyTypeSystem = new DecompilerTypeSystem(testAssembly.GetMetadataFileOrNull(), testAssembly.GetAssemblyResolver()); - language = new CSharpLanguage([]); + language = new CSharpLanguage(); } [Test] diff --git a/ILSpy/AboutPage.cs b/ILSpy/AboutPage.cs index 5683b253de..525d9b8921 100644 --- a/ILSpy/AboutPage.cs +++ b/ILSpy/AboutPage.cs @@ -17,6 +17,7 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Collections.Generic; using System.Composition; using System.IO; using System.Text.RegularExpressions; @@ -28,6 +29,7 @@ using ICSharpCode.AvalonEdit.Rendering; using ICSharpCode.Decompiler; +using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.Themes; @@ -38,17 +40,22 @@ namespace ICSharpCode.ILSpy { [ExportMainMenuCommand(ParentMenuID = nameof(Resources._Help), Header = nameof(Resources._About), MenuOrder = 99999)] [Shared] - sealed class AboutPage : SimpleCommand + public sealed class AboutPageCommand(AssemblyTreeModel assemblyTreeModel) : SimpleCommand { public override void Execute(object parameter) { - MainWindow.Instance.AssemblyTreeModel.NavigateTo( + assemblyTreeModel.NavigateTo( new RequestNavigateEventArgs(new Uri("resource://aboutpage"), null), inNewTabPage: true ); } + } - public static void Display(DecompilerTextView textView) + [Export] + [Shared] + public sealed class AboutPage(IEnumerable aboutPageAdditions) + { + public void Display(DecompilerTextView textView) { AvalonEditTextOutput output = new AvalonEditTextOutput() { Title = Resources.About, @@ -86,7 +93,7 @@ public static void Display(DecompilerTextView textView) }); output.WriteLine(); - foreach (var plugin in App.ExportProvider.GetExportedValues()) + foreach (var plugin in aboutPageAdditions) plugin.Write(output); output.WriteLine(); output.Address = new Uri("resource://AboutPage"); diff --git a/ILSpy/Analyzers/AnalyzeCommand.cs b/ILSpy/Analyzers/AnalyzeCommand.cs index e29dacb23e..30c5a9ee7b 100644 --- a/ILSpy/Analyzers/AnalyzeCommand.cs +++ b/ILSpy/Analyzers/AnalyzeCommand.cs @@ -20,17 +20,18 @@ using System.Linq; using ICSharpCode.Decompiler.TypeSystem; +using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.TreeNodes; +using TomsToolbox.Composition; + namespace ICSharpCode.ILSpy.Analyzers { [ExportContextMenuEntry(Header = nameof(Resources.Analyze), Icon = "Images/Search", Category = nameof(Resources.Analyze), InputGestureText = "Ctrl+R", Order = 100)] [Shared] - internal sealed class AnalyzeContextMenuCommand : IContextMenuEntry + internal sealed class AnalyzeContextMenuCommand(AnalyzerTreeViewModel analyzerTreeView) : IContextMenuEntry { - private static readonly AnalyzerTreeViewModel AnalyzerTreeView = App.ExportProvider.GetExportedValue(); - public bool IsVisible(TextViewContext context) { if (context.TreeView is AnalyzerTreeView && context.SelectedTreeNodes != null && context.SelectedTreeNodes.All(n => n.Parent.IsRoot)) @@ -62,30 +63,28 @@ public void Execute(TextViewContext context) { foreach (var node in context.SelectedTreeNodes.OfType().ToArray()) { - AnalyzerTreeView.Analyze(node.Member); + analyzerTreeView.Analyze(node.Member); } } else if (context.Reference is { Reference: IEntity entity }) { - AnalyzerTreeView.Analyze(entity); + analyzerTreeView.Analyze(entity); } } } - internal sealed class AnalyzeCommand : SimpleCommand + public sealed class AnalyzeCommand(AssemblyTreeModel assemblyTreeModel, AnalyzerTreeViewModel analyzerTreeViewModel) : SimpleCommand { - private static readonly AnalyzerTreeViewModel AnalyzerTreeView = App.ExportProvider.GetExportedValue(); - public override bool CanExecute(object parameter) { - return MainWindow.Instance.AssemblyTreeModel.SelectedNodes.All(n => n is IMemberTreeNode); + return assemblyTreeModel.SelectedNodes.All(n => n is IMemberTreeNode); } public override void Execute(object parameter) { - foreach (var node in MainWindow.Instance.AssemblyTreeModel.SelectedNodes.OfType()) + foreach (var node in assemblyTreeModel.SelectedNodes.OfType()) { - AnalyzerTreeView.Analyze(node.Member); + analyzerTreeViewModel.Analyze(node.Member); } } } diff --git a/ILSpy/Analyzers/AnalyzerSearchTreeNode.cs b/ILSpy/Analyzers/AnalyzerSearchTreeNode.cs index 7c3d484bcd..8609fc6743 100644 --- a/ILSpy/Analyzers/AnalyzerSearchTreeNode.cs +++ b/ILSpy/Analyzers/AnalyzerSearchTreeNode.cs @@ -61,7 +61,7 @@ protected IEnumerable FetchChildren(CancellationToken ct) var context = new AnalyzerContext() { CancellationToken = ct, Language = Language, - AssemblyList = MainWindow.Instance.AssemblyTreeModel.AssemblyList + AssemblyList = AssemblyTreeModel.AssemblyList }; var results = analyzer.Analyze(symbol, context).Select(SymbolTreeNodeFactory); if (context.SortResults) diff --git a/ILSpy/Analyzers/AnalyzerTreeNode.cs b/ILSpy/Analyzers/AnalyzerTreeNode.cs index d2cffeb49f..2775634a61 100644 --- a/ILSpy/Analyzers/AnalyzerTreeNode.cs +++ b/ILSpy/Analyzers/AnalyzerTreeNode.cs @@ -17,15 +17,20 @@ // DEALINGS IN THE SOFTWARE. using System.Collections.Generic; +using System.Linq; +using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpyX; +using ICSharpCode.ILSpyX.Analyzers; using ICSharpCode.ILSpyX.TreeView; +using TomsToolbox.Composition; + namespace ICSharpCode.ILSpy.Analyzers { public abstract class AnalyzerTreeNode : SharpTreeNode { - public Language Language => LanguageService.Instance.Language; + public static Language Language => App.ExportProvider.GetExportedValue().Language; public override bool CanDelete() { @@ -42,6 +47,13 @@ public override void Delete() DeleteCore(); } + public static AssemblyTreeModel AssemblyTreeModel { get; } = App.ExportProvider.GetExportedValue(); + + public static ICollection> Analyzers => App.ExportProvider + .GetExports("Analyzer") + .OrderBy(item => item.Metadata?.Order) + .ToArray(); + /// /// Handles changes to the assembly list. /// diff --git a/ILSpy/Analyzers/AnalyzerTreeViewModel.cs b/ILSpy/Analyzers/AnalyzerTreeViewModel.cs index ce45558b92..c325d01516 100644 --- a/ILSpy/Analyzers/AnalyzerTreeViewModel.cs +++ b/ILSpy/Analyzers/AnalyzerTreeViewModel.cs @@ -24,6 +24,7 @@ using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.ILSpy.Analyzers.TreeNodes; +using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.ViewModels; @@ -38,12 +39,12 @@ public class AnalyzerTreeViewModel : ToolPaneModel { public const string PaneContentId = "analyzerPane"; - public AnalyzerTreeViewModel() + public AnalyzerTreeViewModel(AssemblyTreeModel assemblyTreeModel) { ContentId = PaneContentId; Title = Properties.Resources.Analyze; ShortcutKey = new(Key.R, ModifierKeys.Control); - AssociatedCommand = ILSpyCommands.Analyze; + AssociatedCommand = new AnalyzeCommand(assemblyTreeModel, this); } public AnalyzerRootNode Root { get; } = new(); diff --git a/ILSpy/Analyzers/TreeNodes/AnalyzedEventTreeNode.cs b/ILSpy/Analyzers/TreeNodes/AnalyzedEventTreeNode.cs index 8b6ff6f033..f8fccd1125 100644 --- a/ILSpy/Analyzers/TreeNodes/AnalyzedEventTreeNode.cs +++ b/ILSpy/Analyzers/TreeNodes/AnalyzedEventTreeNode.cs @@ -17,15 +17,12 @@ // DEALINGS IN THE SOFTWARE. using System; -using System.Linq; +using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.ILSpy.TreeNodes; namespace ICSharpCode.ILSpy.Analyzers.TreeNodes { - using ICSharpCode.Decompiler.TypeSystem; - using ICSharpCode.ILSpyX.Analyzers; - internal sealed class AnalyzedEventTreeNode : AnalyzerEntityTreeNode { readonly IEvent analyzedEvent; @@ -54,16 +51,12 @@ protected override void LoadChildren() if (TryFindBackingField(analyzedEvent, out var backingField)) this.Children.Add(new AnalyzedFieldTreeNode(backingField)); - //foreach (var accessor in analyzedEvent.OtherMethods) - // this.Children.Add(new AnalyzedAccessorTreeNode(accessor, null)); - - var analyzers = App.ExportProvider.GetExports("Analyzer"); - foreach (var lazy in analyzers.OrderBy(item => item.Metadata.Order)) + foreach (var lazy in Analyzers) { var analyzer = lazy.Value; if (analyzer.Show(analyzedEvent)) { - this.Children.Add(new AnalyzerSearchTreeNode(analyzedEvent, analyzer, lazy.Metadata.Header)); + this.Children.Add(new AnalyzerSearchTreeNode(analyzedEvent, analyzer, lazy.Metadata?.Header)); } } } @@ -73,7 +66,7 @@ bool TryFindBackingField(IEvent analyzedEvent, out IField backingField) backingField = null; foreach (var field in analyzedEvent.DeclaringTypeDefinition.GetFields(options: GetMemberOptions.IgnoreInheritedMembers)) { - if (field.Name == analyzedEvent.Name && field.Accessibility == Accessibility.Private) + if (field.Name == analyzedEvent.Name && field.Accessibility == Decompiler.TypeSystem.Accessibility.Private) { backingField = field; return true; diff --git a/ILSpy/Analyzers/TreeNodes/AnalyzedFieldTreeNode.cs b/ILSpy/Analyzers/TreeNodes/AnalyzedFieldTreeNode.cs index 1f2b9b9a3f..7317841d1b 100644 --- a/ILSpy/Analyzers/TreeNodes/AnalyzedFieldTreeNode.cs +++ b/ILSpy/Analyzers/TreeNodes/AnalyzedFieldTreeNode.cs @@ -17,11 +17,9 @@ // DEALINGS IN THE SOFTWARE. using System; -using System.Linq; using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.ILSpy.TreeNodes; -using ICSharpCode.ILSpyX.Analyzers; namespace ICSharpCode.ILSpy.Analyzers.TreeNodes { @@ -41,13 +39,12 @@ public AnalyzedFieldTreeNode(IField analyzedField) protected override void LoadChildren() { - var analyzers = App.ExportProvider.GetExports("Analyzer"); - foreach (var lazy in analyzers.OrderBy(item => item.Metadata.Order)) + foreach (var lazy in Analyzers) { var analyzer = lazy.Value; if (analyzer.Show(analyzedField)) { - this.Children.Add(new AnalyzerSearchTreeNode(analyzedField, analyzer, lazy.Metadata.Header)); + this.Children.Add(new AnalyzerSearchTreeNode(analyzedField, analyzer, lazy.Metadata?.Header)); } } } diff --git a/ILSpy/Analyzers/TreeNodes/AnalyzedMethodTreeNode.cs b/ILSpy/Analyzers/TreeNodes/AnalyzedMethodTreeNode.cs index b7cee8ede4..283b30a3fb 100644 --- a/ILSpy/Analyzers/TreeNodes/AnalyzedMethodTreeNode.cs +++ b/ILSpy/Analyzers/TreeNodes/AnalyzedMethodTreeNode.cs @@ -17,11 +17,9 @@ // DEALINGS IN THE SOFTWARE. using System; -using System.Linq; using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.ILSpy.TreeNodes; -using ICSharpCode.ILSpyX.Analyzers; namespace ICSharpCode.ILSpy.Analyzers.TreeNodes { @@ -43,8 +41,7 @@ public AnalyzedMethodTreeNode(IMethod analyzedMethod, string prefix = "") protected override void LoadChildren() { - var analyzers = App.ExportProvider.GetExports("Analyzer"); - foreach (var lazy in analyzers.OrderBy(item => item.Metadata.Order)) + foreach (var lazy in Analyzers) { var analyzer = lazy.Value; if (analyzer.Show(analyzedMethod)) diff --git a/ILSpy/Analyzers/TreeNodes/AnalyzedModuleTreeNode.cs b/ILSpy/Analyzers/TreeNodes/AnalyzedModuleTreeNode.cs index 7f343fb785..a850961476 100644 --- a/ILSpy/Analyzers/TreeNodes/AnalyzedModuleTreeNode.cs +++ b/ILSpy/Analyzers/TreeNodes/AnalyzedModuleTreeNode.cs @@ -17,11 +17,9 @@ // DEALINGS IN THE SOFTWARE. using System; -using System.Linq; using System.Windows; using ICSharpCode.Decompiler.TypeSystem; -using ICSharpCode.ILSpyX.Analyzers; using ICSharpCode.ILSpyX.TreeView.PlatformAbstractions; namespace ICSharpCode.ILSpy.Analyzers.TreeNodes @@ -42,8 +40,7 @@ public AnalyzedModuleTreeNode(IModule analyzedModule) protected override void LoadChildren() { - var analyzers = App.ExportProvider.GetExports("Analyzer"); - foreach (var lazy in analyzers.OrderBy(item => item.Metadata.Order)) + foreach (var lazy in Analyzers) { var analyzer = lazy.Value; if (analyzer.Show(analyzedModule)) diff --git a/ILSpy/Analyzers/TreeNodes/AnalyzedPropertyTreeNode.cs b/ILSpy/Analyzers/TreeNodes/AnalyzedPropertyTreeNode.cs index d19bc3e730..7a4d2fdfaf 100644 --- a/ILSpy/Analyzers/TreeNodes/AnalyzedPropertyTreeNode.cs +++ b/ILSpy/Analyzers/TreeNodes/AnalyzedPropertyTreeNode.cs @@ -17,11 +17,9 @@ // DEALINGS IN THE SOFTWARE. using System; -using System.Linq; using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.ILSpy.TreeNodes; -using ICSharpCode.ILSpyX.Analyzers; namespace ICSharpCode.ILSpy.Analyzers.TreeNodes { @@ -48,11 +46,8 @@ protected override void LoadChildren() this.Children.Add(new AnalyzedAccessorTreeNode(analyzedProperty.Getter, "get")); if (analyzedProperty.CanSet) this.Children.Add(new AnalyzedAccessorTreeNode(analyzedProperty.Setter, "set")); - //foreach (var accessor in analyzedProperty.OtherMethods) - // this.Children.Add(new AnalyzedPropertyAccessorTreeNode(accessor, null)); - var analyzers = App.ExportProvider.GetExports("Analyzer"); - foreach (var lazy in analyzers.OrderBy(item => item.Metadata.Order)) + foreach (var lazy in Analyzers) { var analyzer = lazy.Value; if (analyzer.Show(analyzedProperty)) diff --git a/ILSpy/Analyzers/TreeNodes/AnalyzedTypeTreeNode.cs b/ILSpy/Analyzers/TreeNodes/AnalyzedTypeTreeNode.cs index 6836944eb2..cb3ccc609f 100644 --- a/ILSpy/Analyzers/TreeNodes/AnalyzedTypeTreeNode.cs +++ b/ILSpy/Analyzers/TreeNodes/AnalyzedTypeTreeNode.cs @@ -17,11 +17,9 @@ // DEALINGS IN THE SOFTWARE. using System; -using System.Linq; using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.ILSpy.TreeNodes; -using ICSharpCode.ILSpyX.Analyzers; namespace ICSharpCode.ILSpy.Analyzers.TreeNodes { @@ -41,8 +39,7 @@ public AnalyzedTypeTreeNode(ITypeDefinition analyzedType) protected override void LoadChildren() { - var analyzers = App.ExportProvider.GetExports("Analyzer"); - foreach (var lazy in analyzers.OrderBy(item => item.Metadata.Order)) + foreach (var lazy in Analyzers) { var analyzer = lazy.Value; if (analyzer.Show(analyzedType)) diff --git a/ILSpy/App.xaml.cs b/ILSpy/App.xaml.cs index 0ae19f9e17..05c0777519 100644 --- a/ILSpy/App.xaml.cs +++ b/ILSpy/App.xaml.cs @@ -71,8 +71,10 @@ public App() var cmdArgs = Environment.GetCommandLineArgs().Skip(1); CommandLineArguments = CommandLineArguments.Create(cmdArgs); + var settingsService = new SettingsService(); + bool forceSingleInstance = (CommandLineArguments.SingleInstance ?? true) - && !SettingsService.Instance.MiscSettings.AllowMultipleInstances; + && !settingsService.MiscSettings.AllowMultipleInstances; if (forceSingleInstance) { SingleInstance.Attach(); // will auto-exit for second instance @@ -81,7 +83,7 @@ public App() InitializeComponent(); - if (!InitializeDependencyInjection(SettingsService.Instance)) + if (!InitializeDependencyInjection(settingsService)) { // There is something completely wrong with DI, probably some service registration is missing => nothing we can do to recover, so stop and shut down. Exit += (_, _) => MessageBox.Show(StartupExceptions.FormatExceptions(), "Sorry we crashed!"); @@ -106,7 +108,7 @@ public App() // Add data templates registered via MEF. Resources.MergedDictionaries.Add(DataTemplateManager.CreateDynamicDataTemplates(ExportProvider)); - var sessionSettings = SettingsService.Instance.SessionSettings; + var sessionSettings = settingsService.SessionSettings; ThemeManager.Current.Theme = sessionSettings.Theme; if (!string.IsNullOrEmpty(sessionSettings.CurrentCulture)) { @@ -129,7 +131,7 @@ public App() MessageBox.Show(unknownArguments, "ILSpy Unknown Command Line Arguments Passed"); } - SettingsService.Instance.AssemblyListManager.CreateDefaultAssemblyLists(); + settingsService.AssemblyListManager.CreateDefaultAssemblyLists(); } public new static App Current => (App)Application.Current; @@ -187,6 +189,10 @@ private static bool InitializeDependencyInjection(SettingsService settingsServic services.BindExports(Assembly.GetExecutingAssembly()); // Add the settings service services.AddSingleton(settingsService); + // Add the export provider + services.AddSingleton(_ => ExportProvider); + // Add the docking manager + services.AddSingleton(serviceProvider => serviceProvider.GetService().DockManager); var serviceProvider = services.BuildServiceProvider(new ServiceProviderOptions { ValidateOnBuild = true }); @@ -209,7 +215,7 @@ protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); - MainWindow = new(); + MainWindow = ExportProvider.GetExportedValue(); MainWindow.Show(); } diff --git a/ILSpy/AssemblyTree/AssemblyTreeModel.cs b/ILSpy/AssemblyTree/AssemblyTreeModel.cs index 954310192a..59d3ba47eb 100644 --- a/ILSpy/AssemblyTree/AssemblyTreeModel.cs +++ b/ILSpy/AssemblyTree/AssemblyTreeModel.cs @@ -47,6 +47,7 @@ using ICSharpCode.ILSpyX.Settings; using ICSharpCode.ILSpyX.TreeView; +using TomsToolbox.Composition; using TomsToolbox.Essentials; using TomsToolbox.Wpf; @@ -67,9 +68,20 @@ public class AssemblyTreeModel : ToolPaneModel private readonly NavigationHistory history = new(); private bool isNavigatingHistory; + private readonly AboutPage aboutPage; + private readonly SearchPaneModel searchPaneModel; + private readonly SettingsService settingsService; + private readonly LanguageService languageService; + private readonly IExportProvider exportProvider; - public AssemblyTreeModel() + public AssemblyTreeModel(AboutPage aboutPage, SearchPaneModel searchPaneModel, SettingsService settingsService, LanguageService languageService, IExportProvider exportProvider) { + this.aboutPage = aboutPage; + this.searchPaneModel = searchPaneModel; + this.settingsService = settingsService; + this.languageService = languageService; + this.exportProvider = exportProvider; + Title = Resources.Assemblies; ContentId = PaneContentId; IsCloseable = false; @@ -80,7 +92,7 @@ public AssemblyTreeModel() refreshThrottle = new DispatcherThrottle(DispatcherPriority.Background, RefreshInternal); - AssemblyList = SettingsService.Instance.CreateEmptyAssemblyList(); + AssemblyList = settingsService.CreateEmptyAssemblyList(); } private void Settings_PropertyChanged(object? sender, PropertyChangedEventArgs e) @@ -151,7 +163,7 @@ private bool HandleCommandLineArguments(CommandLineArguments args) { LoadAssemblies(args.AssembliesToLoad, commandLineLoadedAssemblies, focusNode: false); if (args.Language != null) - LanguageService.Instance.Language = LanguageService.Instance.GetLanguage(args.Language); + languageService.Language = languageService.GetLanguage(args.Language); return true; } @@ -161,7 +173,7 @@ private bool HandleCommandLineArguments(CommandLineArguments args) /// private async Task HandleCommandLineArgumentsAfterShowList(CommandLineArguments args, ISettingsProvider? spySettings = null) { - var sessionSettings = SettingsService.Instance.SessionSettings; + var sessionSettings = settingsService.SessionSettings; var relevantAssemblies = commandLineLoadedAssemblies.ToList(); commandLineLoadedAssemblies.Clear(); // clear references once we don't need them anymore @@ -170,10 +182,8 @@ private async Task HandleCommandLineArgumentsAfterShowList(CommandLineArguments if (args.Search != null) { - var searchPane = App.ExportProvider.GetExportedValue(); - - searchPane.SearchTerm = args.Search; - searchPane.Show(); + this.searchPaneModel.SearchTerm = args.Search; + this.searchPaneModel.Show(); } } @@ -290,11 +300,11 @@ private async Task NavigateOnLaunch(string? navigateTo, string[]? activeTreeView SelectNode(node); // only if not showing the about page, perform the update check: - await MainWindow.Instance.ShowMessageIfUpdatesAvailableAsync(spySettings); + await App.Current.MainWindow.ShowMessageIfUpdatesAvailableAsync(spySettings); } else { - DockWorkspace.Instance.ActiveTabPage.ShowTextView(AboutPage.Display); + DockWorkspace.Instance.ActiveTabPage.ShowTextView(aboutPage.Display); } } } @@ -363,11 +373,11 @@ private static bool CanResolveTypeInPEFile(MetadataFile module, ITypeReference t public void Initialize() { - AssemblyList = SettingsService.Instance.LoadInitialAssemblyList(); + AssemblyList = settingsService.LoadInitialAssemblyList(); HandleCommandLineArguments(App.CommandLineArguments); - var loadPreviousAssemblies = SettingsService.Instance.MiscSettings.LoadPreviousAssemblies; + var loadPreviousAssemblies = settingsService.MiscSettings.LoadPreviousAssemblies; if (AssemblyList.GetAssemblies().Length == 0 && AssemblyList.ListName == AssemblyListManager.DefaultListName && loadPreviousAssemblies) @@ -377,7 +387,7 @@ public void Initialize() ShowAssemblyList(AssemblyList); - var sessionSettings = SettingsService.Instance.SessionSettings; + var sessionSettings = settingsService.SessionSettings; if (sessionSettings.ActiveAutoLoadedAssembly != null && File.Exists(sessionSettings.ActiveAutoLoadedAssembly)) { @@ -389,7 +399,7 @@ public void Initialize() private async Task OpenAssemblies() { - await HandleCommandLineArgumentsAfterShowList(App.CommandLineArguments, SettingsService.Instance.SpySettings); + await HandleCommandLineArgumentsAfterShowList(App.CommandLineArguments, settingsService.SpySettings); if (FormatExceptions(App.StartupExceptions.ToArray(), out var output)) { @@ -416,7 +426,7 @@ private static bool FormatExceptions(App.ExceptionData[] exceptions, [NotNullWhe private void ShowAssemblyList(string name) { - AssemblyList list = SettingsService.Instance.AssemblyListManager.LoadList(name); + AssemblyList list = settingsService.AssemblyListManager.LoadList(name); //Only load a new list when it is a different one if (list.ListName != AssemblyList.ListName) { @@ -655,8 +665,7 @@ private Task JumpToReferenceAsync(object? reference, bool inNewTabPage = false) } if (protocol != "decompile") { - var protocolHandlers = App.ExportProvider.GetExportedValues(); - foreach (var handler in protocolHandlers) + foreach (var handler in exportProvider.GetExportedValues()) { var node = handler.Resolve(protocol, file, unresolvedEntity.Handle, out bool newTabPage); if (node != null) @@ -793,7 +802,7 @@ public void DecompileSelectedNodes(DecompilerTextViewState? newState = null) return; } - var options = LanguageService.Instance.CreateDecompilationOptions(activeTabPage); + var options = activeTabPage.CreateDecompilationOptions(); options.TextViewState = newState; activeTabPage.ShowTextViewAsync(textView => textView.DecompileAsync(this.CurrentLanguage, this.SelectedNodes, options)); } @@ -803,9 +812,9 @@ public void RefreshDecompiledView() DecompileSelectedNodes(DockWorkspace.Instance.ActiveTabPage.GetState() as DecompilerTextViewState); } - public Language CurrentLanguage => LanguageService.Instance.Language; + public Language CurrentLanguage => languageService.Language; - public LanguageVersion? CurrentLanguageVersion => LanguageService.Instance.LanguageVersion; + public LanguageVersion? CurrentLanguageVersion => languageService.LanguageVersion; public IEnumerable SelectedNodes { get { @@ -858,7 +867,7 @@ public void NavigateTo(RequestNavigateEventArgs e, bool inNewTabPage = false) if (e.Uri.Host == "aboutpage") { RecordHistory(); - DockWorkspace.Instance.ActiveTabPage.ShowTextView(AboutPage.Display); + DockWorkspace.Instance.ActiveTabPage.ShowTextView(aboutPage.Display); e.Handled = true; return; } @@ -912,7 +921,7 @@ private void RefreshInternal() { var path = GetPathForNode(SelectedItem); - ShowAssemblyList(SettingsService.Instance.AssemblyListManager.LoadList(AssemblyList.ListName)); + ShowAssemblyList(settingsService.AssemblyListManager.LoadList(AssemblyList.ListName)); SelectNode(FindNodeByPath(path, true), inNewTabPage: false); RefreshDecompiledView(); diff --git a/ILSpy/Commands/CheckForUpdatesCommand.cs b/ILSpy/Commands/CheckForUpdatesCommand.cs index 75ab702e73..5ac9b1fc63 100644 --- a/ILSpy/Commands/CheckForUpdatesCommand.cs +++ b/ILSpy/Commands/CheckForUpdatesCommand.cs @@ -25,16 +25,11 @@ namespace ICSharpCode.ILSpy { [ExportMainMenuCommand(ParentMenuID = nameof(Resources._Help), Header = nameof(Resources._CheckUpdates), MenuOrder = 5000)] [Shared] - sealed class CheckForUpdatesCommand : SimpleCommand + sealed class CheckForUpdatesCommand(SettingsService settingsService) : SimpleCommand { - public override bool CanExecute(object parameter) - { - return base.CanExecute(parameter); - } - public override async void Execute(object parameter) { - await MainWindow.Instance.ShowMessageIfUpdatesAvailableAsync(SettingsService.Instance.SpySettings, forceCheck: true); + await App.Current.MainWindow.ShowMessageIfUpdatesAvailableAsync(settingsService.SpySettings, forceCheck: true); } } } diff --git a/ILSpy/Commands/DecompileAllCommand.cs b/ILSpy/Commands/DecompileAllCommand.cs index 72aae604c5..06c093a44e 100644 --- a/ILSpy/Commands/DecompileAllCommand.cs +++ b/ILSpy/Commands/DecompileAllCommand.cs @@ -27,24 +27,19 @@ using System.Threading.Tasks; using ICSharpCode.Decompiler; +using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.TextView; +using ICSharpCode.ILSpy.ViewModels; using ICSharpCode.ILSpyX; namespace ICSharpCode.ILSpy { [ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.DEBUGDecompile), MenuCategory = nameof(Resources.Open), MenuOrder = 2.5)] [Shared] - sealed class DecompileAllCommand : SimpleCommand + sealed class DecompileAllCommand(AssemblyTreeModel assemblyTreeModel, LanguageService languageService) : SimpleCommand { - private readonly IReadOnlyCollection resourceFileHandlers; - - public DecompileAllCommand(IEnumerable resourceFileHandlers) - { - this.resourceFileHandlers = resourceFileHandlers.ToArray(); - } - public override bool CanExecute(object parameter) { return System.IO.Directory.Exists("c:\\temp\\decompiled"); @@ -55,7 +50,7 @@ public override void Execute(object parameter) Docking.DockWorkspace.Instance.RunWithCancellation(ct => Task.Factory.StartNew(() => { AvalonEditTextOutput output = new AvalonEditTextOutput(); Parallel.ForEach( - Partitioner.Create(MainWindow.Instance.AssemblyTreeModel.AssemblyList.GetAssemblies(), loadBalance: true), + Partitioner.Create(assemblyTreeModel.AssemblyList.GetAssemblies(), loadBalance: true), new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount, CancellationToken = ct }, delegate (LoadedAssembly asm) { if (!asm.HasLoadError) @@ -66,10 +61,10 @@ public override void Execute(object parameter) { try { - var options = LanguageService.Instance.CreateDecompilationOptions(DockWorkspace.Instance.ActiveTabPage); + var options = DockWorkspace.Instance.ActiveTabPage.CreateDecompilationOptions(); options.CancellationToken = ct; options.FullDecompilation = true; - new CSharpLanguage(resourceFileHandlers).DecompileAssembly(asm, new PlainTextOutput(writer), options); + new CSharpLanguage().DecompileAssembly(asm, new PlainTextOutput(writer), options); } catch (Exception ex) { @@ -96,15 +91,15 @@ public override void Execute(object parameter) [ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.DEBUGDecompile100x), MenuCategory = nameof(Resources.Open), MenuOrder = 2.6)] [Shared] - sealed class Decompile100TimesCommand : SimpleCommand + sealed class Decompile100TimesCommand(AssemblyTreeModel assemblyTreeModel, LanguageService languageService) : SimpleCommand { public override void Execute(object parameter) { const int numRuns = 100; - var language = LanguageService.Instance.Language; - var nodes = MainWindow.Instance.AssemblyTreeModel.SelectedNodes.ToArray(); + var language = languageService.Language; + var nodes = assemblyTreeModel.SelectedNodes.ToArray(); DockWorkspace dockWorkspace = DockWorkspace.Instance; - var options = LanguageService.Instance.CreateDecompilationOptions(dockWorkspace.ActiveTabPage); + var options = dockWorkspace.ActiveTabPage.CreateDecompilationOptions(); dockWorkspace.RunWithCancellation(ct => Task.Factory.StartNew(() => { options.CancellationToken = ct; Stopwatch w = Stopwatch.StartNew(); diff --git a/ILSpy/Commands/DisassembleAllCommand.cs b/ILSpy/Commands/DisassembleAllCommand.cs index fea58925d9..8b81e87b24 100644 --- a/ILSpy/Commands/DisassembleAllCommand.cs +++ b/ILSpy/Commands/DisassembleAllCommand.cs @@ -24,14 +24,16 @@ using System.Diagnostics; using System.Threading.Tasks; +using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.TextView; +using ICSharpCode.ILSpy.ViewModels; namespace ICSharpCode.ILSpy { [ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.DEBUGDisassemble), MenuCategory = nameof(Resources.Open), MenuOrder = 2.5)] [Shared] - sealed class DisassembleAllCommand : SimpleCommand + sealed class DisassembleAllCommand(AssemblyTreeModel assemblyTreeModel, LanguageService languageService) : SimpleCommand { public override bool CanExecute(object parameter) { @@ -45,7 +47,7 @@ public override void Execute(object parameter) dockWorkspace.RunWithCancellation(ct => Task.Factory.StartNew(() => { AvalonEditTextOutput output = new(); Parallel.ForEach( - Partitioner.Create(MainWindow.Instance.AssemblyTreeModel.AssemblyList.GetAssemblies(), loadBalance: true), + Partitioner.Create(assemblyTreeModel.AssemblyList.GetAssemblies(), loadBalance: true), new() { MaxDegreeOfParallelism = Environment.ProcessorCount, CancellationToken = ct }, asm => { if (!asm.HasLoadError) @@ -56,7 +58,7 @@ public override void Execute(object parameter) { try { - var options = LanguageService.Instance.CreateDecompilationOptions(dockWorkspace.ActiveTabPage); + var options = dockWorkspace.ActiveTabPage.CreateDecompilationOptions(); options.FullDecompilation = true; options.CancellationToken = ct; new ILLanguage().DecompileAssembly(asm, new Decompiler.PlainTextOutput(writer), options); diff --git a/ILSpy/Commands/ExitCommand.cs b/ILSpy/Commands/ExitCommand.cs index 1ba8a34e1d..67f698bfee 100644 --- a/ILSpy/Commands/ExitCommand.cs +++ b/ILSpy/Commands/ExitCommand.cs @@ -27,7 +27,7 @@ sealed class ExitCommand : SimpleCommand { public override void Execute(object parameter) { - MainWindow.Instance.Close(); + App.Current.MainWindow.Close(); } } } \ No newline at end of file diff --git a/ILSpy/Commands/GeneratePdbContextMenuEntry.cs b/ILSpy/Commands/GeneratePdbContextMenuEntry.cs index d31a3160c3..63f38d95f2 100644 --- a/ILSpy/Commands/GeneratePdbContextMenuEntry.cs +++ b/ILSpy/Commands/GeneratePdbContextMenuEntry.cs @@ -29,10 +29,12 @@ using ICSharpCode.Decompiler.CSharp.ProjectDecompiler; using ICSharpCode.Decompiler.DebugInfo; using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TreeNodes; +using ICSharpCode.ILSpy.ViewModels; using ICSharpCode.ILSpyX; using Microsoft.Win32; @@ -41,14 +43,14 @@ namespace ICSharpCode.ILSpy { [ExportContextMenuEntry(Header = nameof(Resources.GeneratePortable))] [Shared] - class GeneratePdbContextMenuEntry : IContextMenuEntry + class GeneratePdbContextMenuEntry(LanguageService languageService) : IContextMenuEntry { public void Execute(TextViewContext context) { var assembly = (context.SelectedTreeNodes?.FirstOrDefault() as AssemblyTreeNode)?.LoadedAssembly; if (assembly == null) return; - GeneratePdbForAssembly(assembly); + GeneratePdbForAssembly(assembly, languageService); } public bool IsEnabled(TextViewContext context) => true; @@ -60,7 +62,7 @@ public bool IsVisible(TextViewContext context) && tn.LoadedAssembly.IsLoadedAsValidAssembly; } - internal static void GeneratePdbForAssembly(LoadedAssembly assembly) + internal static void GeneratePdbForAssembly(LoadedAssembly assembly, LanguageService languageService) { var file = assembly.GetMetadataFileOrNull() as PEFile; if (!PortablePdbWriter.HasCodeViewDebugDirectoryEntry(file)) @@ -75,7 +77,7 @@ internal static void GeneratePdbForAssembly(LoadedAssembly assembly) if (dlg.ShowDialog() != true) return; DockWorkspace dockWorkspace = DockWorkspace.Instance; - DecompilationOptions options = LanguageService.Instance.CreateDecompilationOptions(dockWorkspace.ActiveTabPage); + DecompilationOptions options = dockWorkspace.ActiveTabPage.CreateDecompilationOptions(); string fileName = dlg.FileName; dockWorkspace.RunWithCancellation(ct => Task.Factory.StartNew(() => { AvalonEditTextOutput output = new AvalonEditTextOutput(); @@ -108,21 +110,21 @@ internal static void GeneratePdbForAssembly(LoadedAssembly assembly) [ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.GeneratePortable), MenuCategory = nameof(Resources.Save))] [Shared] - class GeneratePdbMainMenuEntry : SimpleCommand + class GeneratePdbMainMenuEntry(AssemblyTreeModel assemblyTreeModel, LanguageService languageService) : SimpleCommand { public override bool CanExecute(object parameter) { - return MainWindow.Instance.AssemblyTreeModel.SelectedNodes?.Count() == 1 - && MainWindow.Instance.AssemblyTreeModel.SelectedNodes?.FirstOrDefault() is AssemblyTreeNode tn + return assemblyTreeModel.SelectedNodes?.Count() == 1 + && assemblyTreeModel.SelectedNodes?.FirstOrDefault() is AssemblyTreeNode tn && !tn.LoadedAssembly.HasLoadError; } public override void Execute(object parameter) { - var assembly = (MainWindow.Instance.AssemblyTreeModel.SelectedNodes?.FirstOrDefault() as AssemblyTreeNode)?.LoadedAssembly; + var assembly = (assemblyTreeModel.SelectedNodes?.FirstOrDefault() as AssemblyTreeNode)?.LoadedAssembly; if (assembly == null) return; - GeneratePdbContextMenuEntry.GeneratePdbForAssembly(assembly); + GeneratePdbContextMenuEntry.GeneratePdbForAssembly(assembly, languageService); } } } diff --git a/ILSpy/Commands/ILSpyCommands.cs b/ILSpy/Commands/ILSpyCommands.cs deleted file mode 100644 index 50ace93798..0000000000 --- a/ILSpy/Commands/ILSpyCommands.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) 2018 Siegfried Pammer -// -// 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.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Input; - -using ICSharpCode.ILSpy.Analyzers; -using ICSharpCode.ILSpy.Commands; - -namespace ICSharpCode.ILSpy -{ - static class ILSpyCommands - { - public static readonly AnalyzeCommand Analyze = new AnalyzeCommand(); - public static readonly ManageAssemblyListsCommand ManageAssemblyListsCommand = new ManageAssemblyListsCommand(); - public static readonly SetThemeCommand SetTheme = new SetThemeCommand(); - } -} diff --git a/ILSpy/Commands/ManageAssemblyListsCommand.cs b/ILSpy/Commands/ManageAssemblyListsCommand.cs index 63ab2f0375..8172f2182b 100644 --- a/ILSpy/Commands/ManageAssemblyListsCommand.cs +++ b/ILSpy/Commands/ManageAssemblyListsCommand.cs @@ -25,12 +25,12 @@ namespace ICSharpCode.ILSpy { [ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.ManageAssembly_Lists), MenuIcon = "Images/AssemblyList", MenuCategory = nameof(Resources.Open), MenuOrder = 1.7)] [Shared] - sealed class ManageAssemblyListsCommand : SimpleCommand + sealed class ManageAssemblyListsCommand(SettingsService settingsService) : SimpleCommand { public override void Execute(object parameter) { - ManageAssemblyListsDialog dlg = new ManageAssemblyListsDialog(); - dlg.Owner = MainWindow.Instance; + ManageAssemblyListsDialog dlg = new ManageAssemblyListsDialog(settingsService); + dlg.Owner = App.Current.MainWindow; dlg.ShowDialog(); } } diff --git a/ILSpy/Commands/OpenFromGacCommand.cs b/ILSpy/Commands/OpenFromGacCommand.cs index c7fd898d04..ba65bfe214 100644 --- a/ILSpy/Commands/OpenFromGacCommand.cs +++ b/ILSpy/Commands/OpenFromGacCommand.cs @@ -43,7 +43,7 @@ public override bool CanExecute(object parameter) public override void Execute(object parameter) { OpenFromGacDialog dlg = new OpenFromGacDialog { - Owner = MainWindow.Instance + Owner = App.Current.MainWindow }; if (dlg.ShowDialog() == true) diff --git a/ILSpy/Commands/Pdb2XmlCommand.cs b/ILSpy/Commands/Pdb2XmlCommand.cs index d4b9a7faeb..14cfbeabec 100644 --- a/ILSpy/Commands/Pdb2XmlCommand.cs +++ b/ILSpy/Commands/Pdb2XmlCommand.cs @@ -26,6 +26,7 @@ using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.Decompiler; +using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TreeNodes; @@ -36,18 +37,18 @@ namespace ICSharpCode.ILSpy { [ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.DEBUGDumpPDBAsXML), MenuCategory = nameof(Resources.Open), MenuOrder = 2.6)] [Shared] - sealed class Pdb2XmlCommand : SimpleCommand + sealed class Pdb2XmlCommand(AssemblyTreeModel assemblyTreeModel) : SimpleCommand { public override bool CanExecute(object parameter) { - var selectedNodes = MainWindow.Instance.AssemblyTreeModel.SelectedNodes; + var selectedNodes = assemblyTreeModel.SelectedNodes; return selectedNodes?.Any() == true && selectedNodes.All(n => n is AssemblyTreeNode asm && !asm.LoadedAssembly.HasLoadError); } public override void Execute(object parameter) { - Execute(MainWindow.Instance.AssemblyTreeModel.SelectedNodes.OfType()); + Execute(assemblyTreeModel.SelectedNodes.OfType()); } internal static void Execute(IEnumerable nodes) diff --git a/ILSpy/Commands/RemoveAssembliesWithLoadErrors.cs b/ILSpy/Commands/RemoveAssembliesWithLoadErrors.cs index 42673e99a7..da67fd5507 100644 --- a/ILSpy/Commands/RemoveAssembliesWithLoadErrors.cs +++ b/ILSpy/Commands/RemoveAssembliesWithLoadErrors.cs @@ -26,15 +26,8 @@ namespace ICSharpCode.ILSpy { [ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources._RemoveAssembliesWithLoadErrors), MenuCategory = nameof(Resources.Remove), MenuOrder = 2.6)] [Shared] - class RemoveAssembliesWithLoadErrors : SimpleCommand + class RemoveAssembliesWithLoadErrors(AssemblyTreeModel assemblyTreeModel) : SimpleCommand { - private readonly AssemblyTreeModel assemblyTreeModel; - - public RemoveAssembliesWithLoadErrors(AssemblyTreeModel assemblyTreeModel) - { - this.assemblyTreeModel = assemblyTreeModel; - } - public override bool CanExecute(object parameter) { return assemblyTreeModel.AssemblyList.GetAssemblies().Any(l => l.HasLoadError); @@ -46,7 +39,7 @@ public override void Execute(object parameter) { if (!assembly.HasLoadError) continue; - var node = MainWindow.Instance.AssemblyTreeModel.FindAssemblyNode(assembly); + var node = assemblyTreeModel.FindAssemblyNode(assembly); if (node != null && node.CanDelete()) node.Delete(); } diff --git a/ILSpy/Commands/SaveCodeContextMenuEntry.cs b/ILSpy/Commands/SaveCodeContextMenuEntry.cs index 14f9fdf503..2dd646450d 100644 --- a/ILSpy/Commands/SaveCodeContextMenuEntry.cs +++ b/ILSpy/Commands/SaveCodeContextMenuEntry.cs @@ -35,11 +35,11 @@ namespace ICSharpCode.ILSpy.TextView { [ExportContextMenuEntry(Header = nameof(Resources._SaveCode), Category = nameof(Resources.Save), Icon = "Images/Save")] [Shared] - sealed class SaveCodeContextMenuEntry : IContextMenuEntry + sealed class SaveCodeContextMenuEntry(LanguageService languageService) : IContextMenuEntry { public void Execute(TextViewContext context) { - Execute(context.SelectedTreeNodes); + Execute(context.SelectedTreeNodes, languageService); } public bool IsEnabled(TextViewContext context) => true; @@ -57,12 +57,11 @@ public static bool CanExecute(IReadOnlyList selectedNodes) || (selectedNodes.Count > 1 && (selectedNodes.All(n => n is AssemblyTreeNode) || selectedNodes.All(n => n is IMemberTreeNode))); } - public static void Execute(IReadOnlyList selectedNodes) + public static void Execute(IReadOnlyList selectedNodes, LanguageService languageService) { - var settingsService = SettingsService.Instance; var dockWorkspace = Docking.DockWorkspace.Instance; - var currentLanguage = LanguageService.Instance.Language; + var currentLanguage = languageService.Language; var tabPage = dockWorkspace.ActiveTabPage; tabPage.ShowTextView(textView => { if (selectedNodes.Count == 1 && selectedNodes[0] is ILSpyTreeNode singleSelection) @@ -88,7 +87,7 @@ public static void Execute(IReadOnlyList selectedNodes) // Fallback: if nobody was able to handle the request, use default behavior. // try to save all nodes to disk. - var options = LanguageService.Instance.CreateDecompilationOptions(dockWorkspace.ActiveTabPage); + var options = dockWorkspace.ActiveTabPage.CreateDecompilationOptions(); options.FullDecompilation = true; textView.SaveToDisk(currentLanguage, selectedNodes.OfType(), options); }); diff --git a/ILSpy/Commands/SaveCommand.cs b/ILSpy/Commands/SaveCommand.cs index 3b1927e219..3281df4560 100644 --- a/ILSpy/Commands/SaveCommand.cs +++ b/ILSpy/Commands/SaveCommand.cs @@ -28,16 +28,8 @@ namespace ICSharpCode.ILSpy { [ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources._SaveCode), MenuIcon = "Images/Save", MenuCategory = nameof(Resources.Save), MenuOrder = 0)] [Shared] - sealed class SaveCommand : CommandWrapper + sealed class SaveCommand(AssemblyTreeModel assemblyTreeModel, LanguageService languageService) : CommandWrapper(ApplicationCommands.Save) { - private AssemblyTreeModel assemblyTreeModel; - - public SaveCommand(AssemblyTreeModel assemblyTreeModel) - : base(ApplicationCommands.Save) - { - this.assemblyTreeModel = assemblyTreeModel; - } - protected override void OnCanExecute(object sender, CanExecuteRoutedEventArgs e) { e.Handled = true; @@ -46,7 +38,7 @@ protected override void OnCanExecute(object sender, CanExecuteRoutedEventArgs e) protected override void OnExecute(object sender, ExecutedRoutedEventArgs e) { - SaveCodeContextMenuEntry.Execute(assemblyTreeModel.SelectedNodes.ToList()); + SaveCodeContextMenuEntry.Execute(assemblyTreeModel.SelectedNodes.ToList(), languageService); } } } diff --git a/ILSpy/Commands/SelectPdbContextMenuEntry.cs b/ILSpy/Commands/SelectPdbContextMenuEntry.cs index e64ec3881d..9c63a8b8c1 100644 --- a/ILSpy/Commands/SelectPdbContextMenuEntry.cs +++ b/ILSpy/Commands/SelectPdbContextMenuEntry.cs @@ -21,6 +21,7 @@ using System.Linq; using ICSharpCode.Decompiler.CSharp.ProjectDecompiler; +using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.TreeNodes; @@ -29,7 +30,7 @@ namespace ICSharpCode.ILSpy { [ExportContextMenuEntry(Header = nameof(Resources.SelectPDB))] [Shared] - class SelectPdbContextMenuEntry : IContextMenuEntry + class SelectPdbContextMenuEntry(AssemblyTreeModel assemblyTreeModel) : IContextMenuEntry { public async void Execute(TextViewContext context) { @@ -48,10 +49,10 @@ public async void Execute(TextViewContext context) await assembly.LoadDebugInfo(dlg.FileName); } - var node = (AssemblyTreeNode)MainWindow.Instance.AssemblyTreeModel.FindNodeByPath(new[] { assembly.FileName }, true); + var node = (AssemblyTreeNode)assemblyTreeModel.FindNodeByPath(new[] { assembly.FileName }, true); node.UpdateToolTip(); - MainWindow.Instance.AssemblyTreeModel.SelectNode(node); - MainWindow.Instance.AssemblyTreeModel.RefreshDecompiledView(); + assemblyTreeModel.SelectNode(node); + assemblyTreeModel.RefreshDecompiledView(); } public bool IsEnabled(TextViewContext context) => true; diff --git a/ILSpy/Commands/SetThemeCommand.cs b/ILSpy/Commands/SetThemeCommand.cs index 1f9a1226c9..006faa1071 100644 --- a/ILSpy/Commands/SetThemeCommand.cs +++ b/ILSpy/Commands/SetThemeCommand.cs @@ -1,13 +1,17 @@  +using System.Composition; + namespace ICSharpCode.ILSpy.Commands { - public class SetThemeCommand : SimpleCommand + [Export] + [Shared] + public class SetThemeCommand(SettingsService settingsService) : SimpleCommand { public override void Execute(object parameter) { if (parameter is string theme) { - SettingsService.Instance.SessionSettings.Theme = theme; + settingsService.SessionSettings.Theme = theme; } } } diff --git a/ILSpy/Commands/SortAssemblyListCommand.cs b/ILSpy/Commands/SortAssemblyListCommand.cs index f3a55682dd..a9434f9c21 100644 --- a/ILSpy/Commands/SortAssemblyListCommand.cs +++ b/ILSpy/Commands/SortAssemblyListCommand.cs @@ -20,6 +20,7 @@ using System.Collections.Generic; using System.Composition; +using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpyX; using ICSharpCode.ILSpyX.TreeView; @@ -29,22 +30,22 @@ namespace ICSharpCode.ILSpy [ExportMainMenuCommand(ParentMenuID = nameof(Resources._View), Header = nameof(Resources.SortAssembly_listName), MenuIcon = "Images/Sort", MenuCategory = nameof(Resources.View))] [ExportToolbarCommand(ToolTip = nameof(Resources.SortAssemblyListName), ToolbarIcon = "Images/Sort", ToolbarCategory = nameof(Resources.View))] [Shared] - sealed class SortAssemblyListCommand : SimpleCommand + sealed class SortAssemblyListCommand(AssemblyTreeModel assemblyTreeModel) : SimpleCommand { public override void Execute(object parameter) { - MainWindow.Instance.AssemblyTreeModel.SortAssemblyList(); + assemblyTreeModel.SortAssemblyList(); } } [ExportMainMenuCommand(ParentMenuID = nameof(Resources._View), Header = nameof(Resources._CollapseTreeNodes), MenuIcon = "Images/CollapseAll", MenuCategory = nameof(Resources.View))] [ExportToolbarCommand(ToolTip = nameof(Resources.CollapseTreeNodes), ToolbarIcon = "Images/CollapseAll", ToolbarCategory = nameof(Resources.View))] [Shared] - sealed class CollapseAllCommand : SimpleCommand + sealed class CollapseAllCommand(AssemblyTreeModel assemblyTreeModel) : SimpleCommand { public override void Execute(object parameter) { - MainWindow.Instance.AssemblyTreeModel.CollapseAll(); + assemblyTreeModel.CollapseAll(); } } diff --git a/ILSpy/ContextMenuEntry.cs b/ILSpy/ContextMenuEntry.cs index 5d80ca5f18..1402a09b03 100644 --- a/ILSpy/ContextMenuEntry.cs +++ b/ILSpy/ContextMenuEntry.cs @@ -31,6 +31,7 @@ using TomsToolbox.Composition; using TomsToolbox.Essentials; +using TomsToolbox.Wpf.Composition; namespace ICSharpCode.ILSpy { @@ -222,7 +223,7 @@ public static void Add(DataGrid dataGrid) private ContextMenuProvider(Control control) { - entries = App.ExportProvider.GetExports().ToArray(); + entries = control.GetExportProvider().GetExports().ToArray(); this.control = control; } diff --git a/ILSpy/Docking/DockWorkspace.cs b/ILSpy/Docking/DockWorkspace.cs index b196f8e79d..af59d3f593 100644 --- a/ILSpy/Docking/DockWorkspace.cs +++ b/ILSpy/Docking/DockWorkspace.cs @@ -32,6 +32,7 @@ using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.ILSpy.Analyzers; +using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpy.Search; using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.ViewModels; @@ -44,15 +45,21 @@ namespace ICSharpCode.ILSpy.Docking { public class DockWorkspace : ObservableObject, ILayoutUpdateStrategy { - private static SessionSettings SessionSettings => SettingsService.Instance.SessionSettings; + private static readonly IExportProvider exportProvider = App.ExportProvider; - private readonly IExportProvider exportProvider = App.ExportProvider; + private static SettingsService SettingsService => exportProvider.GetExportedValue(); + + private static LanguageService LanguageService => exportProvider.GetExportedValue(); + + private static SessionSettings SessionSettings => SettingsService.SessionSettings; public static readonly DockWorkspace Instance = new(); private readonly ObservableCollection tabPages = []; - private DockingManager dockingManager; + private DockingManager DockingManager => exportProvider.GetExportedValue(); + + AssemblyTreeModel AssemblyTreeModel => exportProvider.GetExportedValue(); private DockWorkspace() { @@ -123,7 +130,7 @@ private void TabPages_CollectionChanged(object sender, NotifyCollectionChangedEv public void AddTabPage(TabPageModel tabPage = null) { - tabPages.Add(tabPage ?? new TabPageModel()); + tabPages.Add(tabPage ?? new TabPageModel(AssemblyTreeModel, SettingsService, LanguageService)); } public ReadOnlyObservableCollection TabPages { get; } @@ -170,29 +177,28 @@ public TabPageModel ActiveTabPage { { if (state.DecompiledNodes != null) { - MainWindow.Instance.AssemblyTreeModel.SelectNodes(state.DecompiledNodes); + AssemblyTreeModel.SelectNodes(state.DecompiledNodes); } else { - MainWindow.Instance.AssemblyTreeModel.NavigateTo(new(state.ViewedUri, null)); + AssemblyTreeModel.NavigateTo(new(state.ViewedUri, null)); } } } } public PaneModel ActivePane { - get => dockingManager?.ActiveContent as PaneModel; + get => DockingManager?.ActiveContent as PaneModel; set { - if (dockingManager is not null) - dockingManager.ActiveContent = value; + if (DockingManager is not null) + DockingManager.ActiveContent = value; } } - public void InitializeLayout(DockingManager manager) + public void InitializeLayout() { - this.dockingManager = manager; - manager.LayoutUpdateStrategy = this; - XmlLayoutSerializer serializer = new XmlLayoutSerializer(manager); + DockingManager.LayoutUpdateStrategy = this; + XmlLayoutSerializer serializer = new XmlLayoutSerializer(DockingManager); serializer.LayoutSerializationCallback += LayoutSerializationCallback; try { @@ -254,8 +260,8 @@ internal void ResetLayout() } CloseAllTabs(); SessionSettings.DockLayout.Reset(); - InitializeLayout(MainWindow.Instance.dockManager); - MainWindow.Instance.Dispatcher.BeginInvoke(DispatcherPriority.Background, (Action)MainWindow.Instance.AssemblyTreeModel.RefreshDecompiledView); + InitializeLayout(); + App.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, AssemblyTreeModel.RefreshDecompiledView); } static readonly PropertyInfo previousContainerProperty = typeof(LayoutContent).GetProperty("PreviousContainer", BindingFlags.NonPublic | BindingFlags.Instance); diff --git a/ILSpy/ExtensionMethods.cs b/ILSpy/ExtensionMethods.cs index 1d49f41ada..bd460826c9 100644 --- a/ILSpy/ExtensionMethods.cs +++ b/ILSpy/ExtensionMethods.cs @@ -76,10 +76,11 @@ public static U[] SelectArray(this ICollection collection, Func f return result; } - public static ICompilation? GetTypeSystemWithCurrentOptionsOrNull(this MetadataFile file) + public static ICompilation? GetTypeSystemWithCurrentOptionsOrNull(this MetadataFile file, SettingsService settingsService) { - return LoadedAssemblyExtensions.GetLoadedAssembly(file) - .GetTypeSystemOrNull(DecompilerTypeSystem.GetOptions(SettingsService.Instance.DecompilerSettings)); + return file + .GetLoadedAssembly() + .GetTypeSystemOrNull(DecompilerTypeSystem.GetOptions(settingsService.DecompilerSettings)); } #region DPI independence diff --git a/ILSpy/Languages/CSharpILMixedLanguage.cs b/ILSpy/Languages/CSharpILMixedLanguage.cs index 93752eaefe..77ec689827 100644 --- a/ILSpy/Languages/CSharpILMixedLanguage.cs +++ b/ILSpy/Languages/CSharpILMixedLanguage.cs @@ -43,13 +43,13 @@ namespace ICSharpCode.ILSpy [Export(typeof(Language))] [Shared] - class CSharpILMixedLanguage : ILLanguage + class CSharpILMixedLanguage(SettingsService settingsService) : ILLanguage { public override string Name => "IL with C#"; protected override ReflectionDisassembler CreateDisassembler(ITextOutput output, DecompilationOptions options) { - var displaySettings = SettingsService.Instance.DisplaySettings; + var displaySettings = settingsService.DisplaySettings; return new ReflectionDisassembler(output, new MixedMethodBodyDisassembler(output, options) { DetectControlStructure = detectControlStructure, diff --git a/ILSpy/Languages/CSharpLanguage.cs b/ILSpy/Languages/CSharpLanguage.cs index 5725e05556..c59a3fec66 100644 --- a/ILSpy/Languages/CSharpLanguage.cs +++ b/ILSpy/Languages/CSharpLanguage.cs @@ -38,6 +38,7 @@ using ICSharpCode.Decompiler.Output; using ICSharpCode.Decompiler.Solution; using ICSharpCode.Decompiler.TypeSystem; +using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpyX; @@ -55,25 +56,18 @@ namespace ICSharpCode.ILSpy [Shared] public class CSharpLanguage : Language { - readonly IReadOnlyCollection resourceFileHandlers; - string name = "C#"; bool showAllMembers = false; int transformCount = int.MaxValue; - public CSharpLanguage(IEnumerable resourceFileHandlers) - { - this.resourceFileHandlers = resourceFileHandlers.ToArray(); - } - #if DEBUG - internal static IEnumerable GetDebugLanguages(IReadOnlyCollection resourceFileHandlers) + internal static IEnumerable GetDebugLanguages() { string lastTransformName = "no transforms"; int transformCount = 0; foreach (var transform in CSharpDecompiler.GetAstTransforms()) { - yield return new CSharpLanguage(resourceFileHandlers) { + yield return new() { transformCount = transformCount, name = "C# - " + lastTransformName, showAllMembers = true @@ -81,7 +75,7 @@ internal static IEnumerable GetDebugLanguages(IReadOnlyCollectio lastTransformName = "after " + transform.GetType().Name; transformCount++; } - yield return new CSharpLanguage(resourceFileHandlers) { + yield return new() { name = "C# - " + lastTransformName, showAllMembers = true }; @@ -364,15 +358,15 @@ public override void DecompileType(ITypeDefinition type, ITextOutput output, Dec void AddReferenceWarningMessage(MetadataFile module, ITextOutput output) { - var loadedAssembly = MainWindow.Instance.AssemblyTreeModel.AssemblyList.GetAssemblies().FirstOrDefault(la => la.GetMetadataFileOrNull() == module); + var loadedAssembly = AssemblyTreeModel.AssemblyList.GetAssemblies().FirstOrDefault(la => la.GetMetadataFileOrNull() == module); if (loadedAssembly == null || !loadedAssembly.LoadedAssemblyReferencesInfo.HasErrors) return; string line1 = Properties.Resources.WarningSomeAssemblyReference; string line2 = Properties.Resources.PropertyManuallyMissingReferencesListLoadedAssemblies; AddWarningMessage(module, output, line1, line2, Properties.Resources.ShowAssemblyLoad, Images.ViewCode, delegate { - ILSpyTreeNode assemblyNode = MainWindow.Instance.AssemblyTreeModel.FindTreeNode(module); + ILSpyTreeNode assemblyNode = AssemblyTreeModel.FindTreeNode(module); assemblyNode.EnsureLazyChildren(); - MainWindow.Instance.AssemblyTreeModel.SelectNode(assemblyNode.Children.OfType().Single()); + AssemblyTreeModel.SelectNode(assemblyNode.Children.OfType().Single()); }); } @@ -436,7 +430,7 @@ public override ProjectId DecompileAssembly(LoadedAssembly assembly, ITextOutput { options.DecompilerSettings.UseSdkStyleProjectFormat = false; } - var decompiler = new ILSpyWholeProjectDecompiler(assembly, options, resourceFileHandlers) { + var decompiler = new ILSpyWholeProjectDecompiler(assembly, options) { ProgressIndicator = options.Progress }; return decompiler.DecompileProject(module, options.SaveAsProjectDirectory, new TextOutputWriter(output), options.CancellationToken); @@ -549,20 +543,18 @@ class ILSpyWholeProjectDecompiler : WholeProjectDecompiler { readonly LoadedAssembly assembly; readonly DecompilationOptions options; - private readonly IReadOnlyCollection resourceFileHandlers; - public ILSpyWholeProjectDecompiler(LoadedAssembly assembly, DecompilationOptions options, IReadOnlyCollection resourceFileHandlers) + public ILSpyWholeProjectDecompiler(LoadedAssembly assembly, DecompilationOptions options) : base(options.DecompilerSettings, assembly.GetAssemblyResolver(options.DecompilerSettings.AutoLoadAssemblyReferences, options.DecompilerSettings.ApplyWindowsRuntimeProjections), null, assembly.GetAssemblyReferenceClassifier(options.DecompilerSettings.ApplyWindowsRuntimeProjections), assembly.GetDebugInfoOrNull()) { this.assembly = assembly; this.options = options; - this.resourceFileHandlers = resourceFileHandlers; } protected override IEnumerable WriteResourceToFile(string fileName, string resourceName, Stream entryStream) { var context = new ResourceFileHandlerContext(options); - foreach (var handler in resourceFileHandlers) + foreach (var handler in ResourceFileHandlers) { if (handler.CanHandle(fileName, context)) { @@ -576,19 +568,19 @@ protected override IEnumerable WriteResourceToFile(string fileN } } - static CSharpAmbience CreateAmbience() + CSharpAmbience CreateAmbience() { CSharpAmbience ambience = new CSharpAmbience(); // Do not forget to update CSharpAmbienceTests.ILSpyMainTreeViewTypeFlags, if this ever changes. ambience.ConversionFlags = ConversionFlags.ShowTypeParameterList | ConversionFlags.PlaceReturnTypeAfterParameterList; - if (SettingsService.Instance.DecompilerSettings.LiftNullables) + if (SettingsService.DecompilerSettings.LiftNullables) { ambience.ConversionFlags |= ConversionFlags.UseNullableSpecifierForValueTypes; } return ambience; } - static string EntityToString(IEntity entity, bool includeDeclaringTypeName, bool includeNamespace, bool includeNamespaceOfDeclaringTypeName) + string EntityToString(IEntity entity, bool includeDeclaringTypeName, bool includeNamespace, bool includeNamespaceOfDeclaringTypeName) { // Do not forget to update CSharpAmbienceTests, if this ever changes. var ambience = CreateAmbience(); @@ -784,7 +776,7 @@ public override string GetEntityName(MetadataFile module, EntityHandle handle, b public override bool ShowMember(IEntity member) { MetadataFile assembly = member.ParentModule.MetadataFile; - return showAllMembers || !CSharpDecompiler.MemberIsHidden(assembly, member.MetadataToken, SettingsService.Instance.DecompilerSettings); + return showAllMembers || !CSharpDecompiler.MemberIsHidden(assembly, member.MetadataToken, SettingsService.DecompilerSettings); } public override RichText GetRichTextTooltip(IEntity entity) @@ -793,7 +785,7 @@ public override RichText GetRichTextTooltip(IEntity entity) var output = new StringWriter(); var decoratedWriter = new TextWriterTokenWriter(output); var writer = new CSharpHighlightingTokenWriter(TokenWriter.InsertRequiredSpaces(decoratedWriter), locatable: decoratedWriter); - var settings = SettingsService.Instance.DecompilerSettings; + var settings = SettingsService.DecompilerSettings; if (!settings.LiftNullables) { flags &= ~ConversionFlags.UseNullableSpecifierForValueTypes; diff --git a/ILSpy/Languages/ILLanguage.cs b/ILSpy/Languages/ILLanguage.cs index a857268f12..31494f7d89 100644 --- a/ILSpy/Languages/ILLanguage.cs +++ b/ILSpy/Languages/ILLanguage.cs @@ -31,6 +31,7 @@ using ICSharpCode.Decompiler.Util; using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.TextView; +using ICSharpCode.ILSpy.ViewModels; using ICSharpCode.ILSpyX; namespace ICSharpCode.ILSpy @@ -58,7 +59,7 @@ public override string FileExtension { protected virtual ReflectionDisassembler CreateDisassembler(ITextOutput output, DecompilationOptions options) { - var displaySettings = SettingsService.Instance.DisplaySettings; + var displaySettings = SettingsService.DisplaySettings; output.IndentationString = options.DecompilerSettings.CSharpFormattingOptions.IndentationString; return new ReflectionDisassembler(output, options.CancellationToken) { DetectControlStructure = detectControlStructure, @@ -198,10 +199,9 @@ public override ProjectId DecompileAssembly(LoadedAssembly assembly, ITextOutput public override RichText GetRichTextTooltip(IEntity entity) { var output = new AvalonEditTextOutput() { IgnoreNewLineAndIndent = true }; - var settingsService = SettingsService.Instance; var dockWorkspace = DockWorkspace.Instance; - var disasm = CreateDisassembler(output, LanguageService.Instance.CreateDecompilationOptions(dockWorkspace.ActiveTabPage)); + var disasm = CreateDisassembler(output, dockWorkspace.ActiveTabPage.CreateDecompilationOptions()); MetadataFile module = entity.ParentModule?.MetadataFile; if (module == null) { diff --git a/ILSpy/Languages/Language.cs b/ILSpy/Languages/Language.cs index 26410fe243..59511f9cb1 100644 --- a/ILSpy/Languages/Language.cs +++ b/ILSpy/Languages/Language.cs @@ -18,6 +18,7 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Reflection.Metadata; using System.Reflection.PortableExecutable; using System.Text; @@ -29,6 +30,7 @@ using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem.Implementation; using ICSharpCode.Decompiler.Util; +using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpyX; using ICSharpCode.ILSpyX.Abstractions; @@ -42,6 +44,12 @@ namespace ICSharpCode.ILSpy /// public abstract class Language : ILanguage { + public static SettingsService SettingsService { get; } = App.ExportProvider.GetExportedValue(); + + public static AssemblyTreeModel AssemblyTreeModel { get; } = App.ExportProvider.GetExportedValue(); + + public static ICollection ResourceFileHandlers { get; } = App.ExportProvider.GetExportedValues().ToArray(); + /// /// Gets the name of the language (as shown in the UI) /// diff --git a/ILSpy/Languages/LanguageService.cs b/ILSpy/Languages/LanguageService.cs index e060c117df..f5282853ca 100644 --- a/ILSpy/Languages/LanguageService.cs +++ b/ILSpy/Languages/LanguageService.cs @@ -21,26 +21,23 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Composition; using System.Linq; -using ICSharpCode.Decompiler; -using ICSharpCode.ILSpy.ViewModels; using ICSharpCode.ILSpyX; using TomsToolbox.Wpf; namespace ICSharpCode.ILSpy { + [Export] + [Shared] public class LanguageService : ObservableObjectBase { - public static readonly LanguageService Instance = new(App.ExportProvider.GetExportedValues(), App.ExportProvider.GetExportedValues(), SettingsService.Instance); - private readonly LanguageSettings languageSettings; - private readonly SettingsService settingsService; - public LanguageService(IEnumerable languages, IEnumerable resourceFileHandlers, SettingsService settingsService) + public LanguageService(IEnumerable languages, SettingsService settingsService) { - this.settingsService = settingsService; languageSettings = settingsService.SessionSettings.LanguageSettings; var sortedLanguages = languages.ToList(); @@ -48,7 +45,7 @@ public LanguageService(IEnumerable languages, IEnumerable string.Compare(a.Name, b.Name, StringComparison.Ordinal)); #if DEBUG sortedLanguages.AddRange(ILAstLanguage.GetDebugLanguages()); - sortedLanguages.AddRange(CSharpLanguage.GetDebugLanguages(resourceFileHandlers.ToArray())); + sortedLanguages.AddRange(CSharpLanguage.GetDebugLanguages()); #endif AllLanguages = sortedLanguages.AsReadOnly(); @@ -143,10 +140,5 @@ public LanguageVersion? LanguageVersion { languageSettings.LanguageVersionId = languageVersion?.Version; } } - - public DecompilationOptions CreateDecompilationOptions(TabPageModel tabPage) - { - return new(LanguageVersion, settingsService.DecompilerSettings, settingsService.DisplaySettings) { Progress = tabPage.Content as IProgress }; - } } } diff --git a/ILSpy/MainWindow.xaml b/ILSpy/MainWindow.xaml index bbefc63fc1..2aece0f63c 100644 --- a/ILSpy/MainWindow.xaml +++ b/ILSpy/MainWindow.xaml @@ -18,6 +18,8 @@ xmlns:themes="clr-namespace:ICSharpCode.ILSpy.Themes" xmlns:toms="urn:TomsToolbox" xmlns:viewModels="clr-namespace:ICSharpCode.ILSpy.ViewModels" + xmlns:composition="urn:TomsToolbox.Composition" + xmlns:commands="clr-namespace:ICSharpCode.ILSpy.Commands" d:DataContext="{d:DesignInstance local:MainWindowViewModel}"> @@ -36,7 +38,7 @@ - + @@ -60,7 +62,7 @@