diff --git a/Fody/AssemblyPathSet.cs b/Fody/AssemblyPathSet.cs new file mode 100644 index 000000000..b02e061e1 --- /dev/null +++ b/Fody/AssemblyPathSet.cs @@ -0,0 +1,33 @@ +using System.Runtime.InteropServices; + +namespace Fody; + +public sealed class AssemblyPathSet : IEquatable +{ + readonly HashSet assemblyPaths; + readonly int hashCode; + + public IReadOnlyCollection AssemblyPaths => assemblyPaths; + + public AssemblyPathSet(IEnumerable paths) + { + var stringComparer = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal; + + assemblyPaths = new(paths, stringComparer); + hashCode = 0; + + foreach (var path in assemblyPaths.OrderBy(i => i, stringComparer)) + { + hashCode = (hashCode * 397) ^ path.GetHashCode(); + } + } + + public bool Equals(AssemblyPathSet? other) => + other is not null && assemblyPaths.SetEquals(other.assemblyPaths); + + public override bool Equals(object? obj) => + obj is AssemblyPathSet other && Equals(other); + + public override int GetHashCode() => + hashCode; +} diff --git a/Fody/Processor.cs b/Fody/Processor.cs index 42b9b5f5f..8e5b666a0 100644 --- a/Fody/Processor.cs +++ b/Fody/Processor.cs @@ -22,8 +22,7 @@ public partial class Processor public bool GenerateXsd; IInnerWeaver? innerWeaver; - static Dictionary solutionAssemblyLoadContexts = - new(StringComparer.OrdinalIgnoreCase); + static Dictionary loadContexts = new(); public ILogger Logger = null!; static readonly object mutex = new(); @@ -147,9 +146,11 @@ void ExecuteInOwnAssemblyLoadContext() IsolatedAssemblyLoadContext GetLoadContext() { - if (solutionAssemblyLoadContexts.TryGetValue(SolutionDirectory, out var loadContext)) + var assemblyPathSet = new AssemblyPathSet(Weavers.Select(weaver => weaver.AssemblyPath)); + + if (loadContexts.TryGetValue(assemblyPathSet, out var loadContext)) { - if (!WeaversHistory.HasChanged(Weavers.Select(_ => _.AssemblyPath))) + if (!WeaversHistory.HasChanged(assemblyPathSet.AssemblyPaths)) { return loadContext; } @@ -158,7 +159,7 @@ IsolatedAssemblyLoadContext GetLoadContext() loadContext.Unload(); } - return solutionAssemblyLoadContexts[SolutionDirectory] = CreateAssemblyLoadContext(); + return loadContexts[assemblyPathSet] = CreateAssemblyLoadContext(); } IsolatedAssemblyLoadContext CreateAssemblyLoadContext() diff --git a/Tests/Fody/AssemblyPathSetTests.cs b/Tests/Fody/AssemblyPathSetTests.cs new file mode 100644 index 000000000..a86481992 --- /dev/null +++ b/Tests/Fody/AssemblyPathSetTests.cs @@ -0,0 +1,23 @@ +namespace Tests.Fody; + +public class AssemblyPathSetTests +{ + [Fact] + public void ShouldDetectEquality() + { + var a = new AssemblyPathSet(["foo", "bar"]); + var b = new AssemblyPathSet(["bar", "foo", "bar"]); + + Assert.Equal(a, b); + Assert.Equal(a.GetHashCode(), b.GetHashCode()); + } + + [Fact] + public void ShouldDetectInequality() + { + var a = new AssemblyPathSet(["foo", "bar"]); + var b = new AssemblyPathSet(["foo", "baz"]); + + Assert.NotEqual(a, b); + } +}