From 8cf0f4f120ac415015638eabb26e0d5e02df7169 Mon Sep 17 00:00:00 2001 From: Jeremy Pritts Date: Sun, 16 Oct 2022 12:53:36 -0400 Subject: [PATCH] Make SignatureComparer immutable and add a default instance --- .../AssemblyResolverBase.cs | 5 +-- .../DefaultMetadataResolver.cs | 5 +-- .../SignatureComparer.ResolutionScope.cs | 45 +++++++++---------- .../Signatures/SignatureComparer.cs | 29 ++++++++++++ .../Signatures/SignatureComparisonFlags.cs | 44 ++++++++++++++++++ 5 files changed, 95 insertions(+), 33 deletions(-) create mode 100644 src/AsmResolver.DotNet/Signatures/SignatureComparisonFlags.cs diff --git a/src/AsmResolver.DotNet/AssemblyResolverBase.cs b/src/AsmResolver.DotNet/AssemblyResolverBase.cs index bd3fa1ac1..64d057c99 100644 --- a/src/AsmResolver.DotNet/AssemblyResolverBase.cs +++ b/src/AsmResolver.DotNet/AssemblyResolverBase.cs @@ -13,10 +13,7 @@ namespace AsmResolver.DotNet public abstract class AssemblyResolverBase : IAssemblyResolver { private static readonly string[] BinaryFileExtensions = {".dll", ".exe"}; - private static readonly SignatureComparer Comparer = new() - { - AcceptNewerAssemblyVersionNumbers = true - }; + private static readonly SignatureComparer Comparer = new(SignatureComparisonFlags.AcceptNewerVersions); private readonly Dictionary _cache = new(new SignatureComparer()); diff --git a/src/AsmResolver.DotNet/DefaultMetadataResolver.cs b/src/AsmResolver.DotNet/DefaultMetadataResolver.cs index 18e57b9e5..fcfc69b8b 100644 --- a/src/AsmResolver.DotNet/DefaultMetadataResolver.cs +++ b/src/AsmResolver.DotNet/DefaultMetadataResolver.cs @@ -13,10 +13,7 @@ namespace AsmResolver.DotNet public class DefaultMetadataResolver : IMetadataResolver { private readonly ConcurrentDictionary _typeCache; - private readonly SignatureComparer _comparer = new() - { - IgnoreAssemblyVersionNumbers = true - }; + private readonly SignatureComparer _comparer = new(SignatureComparisonFlags.VersionAgnostic); /// /// Creates a new metadata resolver. diff --git a/src/AsmResolver.DotNet/Signatures/SignatureComparer.ResolutionScope.cs b/src/AsmResolver.DotNet/Signatures/SignatureComparer.ResolutionScope.cs index 5eedef741..31fdb7eac 100644 --- a/src/AsmResolver.DotNet/Signatures/SignatureComparer.ResolutionScope.cs +++ b/src/AsmResolver.DotNet/Signatures/SignatureComparer.ResolutionScope.cs @@ -8,35 +8,28 @@ public partial class SignatureComparer : IEqualityComparer, IEqualityComparer { - /// - /// Gets or sets a value indicating whether version numbers should be excluded in the comparison of two - /// assembly descriptors. - /// - public bool IgnoreAssemblyVersionNumbers + private bool IgnoreAssemblyVersionNumbers { - get; - set; + get + { + return (Flags & SignatureComparisonFlags.VersionAgnostic) == SignatureComparisonFlags.VersionAgnostic; + } } - /// - /// Gets or sets a value indicating whether the containing assembly of the second member to compare is - /// allowed to be a newer version than the containing assembly of the first member. - /// - /// - /// - /// If this property is set to true, then any member reference that is contained in a certain - /// assembly (e.g. with version 1.0.0.0), will be considered equal to a member reference with the - /// same name or signature contained in an assembly with a newer version (e.g. 1.1.0.0). When this - /// property is set to false, the exact version number must match instead. - /// - /// - /// This property is ignored if is true. - /// - /// - public bool AcceptNewerAssemblyVersionNumbers + private bool AcceptNewerAssemblyVersionNumbers { - get; - set; + get + { + return (Flags & SignatureComparisonFlags.AcceptNewerVersions) == SignatureComparisonFlags.AcceptNewerVersions; + } + } + + private bool AcceptOlderAssemblyVersionNumbers + { + get + { + return (Flags & SignatureComparisonFlags.AcceptOlderVersions) == SignatureComparisonFlags.AcceptOlderVersions; + } } /// @@ -80,6 +73,8 @@ public bool Equals(AssemblyDescriptor? x, AssemblyDescriptor? y) versionMatch = true; else if (AcceptNewerAssemblyVersionNumbers) versionMatch = x.Version <= y.Version; + else if (AcceptOlderAssemblyVersionNumbers) + versionMatch = x.Version >= y.Version; else versionMatch = x.Version == y.Version; diff --git a/src/AsmResolver.DotNet/Signatures/SignatureComparer.cs b/src/AsmResolver.DotNet/Signatures/SignatureComparer.cs index 09b9843ff..c4a67b84d 100644 --- a/src/AsmResolver.DotNet/Signatures/SignatureComparer.cs +++ b/src/AsmResolver.DotNet/Signatures/SignatureComparer.cs @@ -9,6 +9,35 @@ public partial class SignatureComparer : IEqualityComparer { private const int ElementTypeOffset = 24; + private const SignatureComparisonFlags DefaultFlags = SignatureComparisonFlags.ExactVersion; + + /// + /// An immutable default instance of . + /// + public static SignatureComparer Default { get; } = new(); + + /// + /// Flags for controlling comparison behavior. + /// + public SignatureComparisonFlags Flags { get; } + + /// + /// The default constructor. + /// + public SignatureComparer() + { + Flags = DefaultFlags; + } + + /// + /// A constructor with a parameter for specifying the + /// used in comparisons. + /// + /// The used in comparisons. + public SignatureComparer(SignatureComparisonFlags flags) + { + Flags = flags; + } /// public bool Equals(byte[]? x, byte[]? y) => ByteArrayEqualityComparer.Instance.Equals(x, y); diff --git a/src/AsmResolver.DotNet/Signatures/SignatureComparisonFlags.cs b/src/AsmResolver.DotNet/Signatures/SignatureComparisonFlags.cs new file mode 100644 index 000000000..698e835cd --- /dev/null +++ b/src/AsmResolver.DotNet/Signatures/SignatureComparisonFlags.cs @@ -0,0 +1,44 @@ +using System; + +namespace AsmResolver.DotNet.Signatures +{ + /// + /// Flags for controlling the behavior of . + /// + [Flags] + public enum SignatureComparisonFlags + { + /// + /// When neither nor are specified, + /// the exact version number must match in the comparison of two assembly descriptors. + /// + ExactVersion = 0, + /// + /// If this flag is used, the containing assembly of the second member to compare is + /// allowed to be an older version than the containing assembly of the first member. + /// + /// + /// If this flag is used, then any member reference that is contained in a certain + /// assembly (e.g. with version 1.1.0.0), will be considered equal to a member reference with the + /// same name or signature contained in an assembly with a older version (e.g. 1.0.0.0). + /// Otherwise, they will be treated as inequal. + /// + AcceptOlderVersions = 1, + /// + /// If this flag is used, the containing assembly of the second member to compare is + /// allowed to be a newer version than the containing assembly of the first member. + /// + /// + /// If this flag is used, then any member reference that is contained in a certain + /// assembly (e.g. with version 1.0.0.0), will be considered equal to a member reference with the + /// same name or signature contained in an assembly with a newer version (e.g. 1.1.0.0). + /// Otherwise, they will be treated as inequal. + /// + AcceptNewerVersions = 2, + /// + /// If this flag is used, version numbers will be excluded in the comparison of two + /// assembly descriptors. + /// + VersionAgnostic = AcceptOlderVersions | AcceptNewerVersions, + } +}