diff --git a/src/Shared/AssemblyNameExtension.cs b/src/Shared/AssemblyNameExtension.cs
index 529335c8bea..482bccd1bba 100644
--- a/src/Shared/AssemblyNameExtension.cs
+++ b/src/Shared/AssemblyNameExtension.cs
@@ -57,7 +57,7 @@ internal enum PartialComparisonFlags : int
/// between the two is done lazily on demand.
///
[Serializable]
- sealed internal class AssemblyNameExtension
+ internal sealed class AssemblyNameExtension
{
private AssemblyName asAssemblyName = null;
private string asString = null;
@@ -592,11 +592,7 @@ internal AssemblyNameExtension Clone()
if (asAssemblyName != null)
{
-#if FEATURE_ASSEMBLYNAME_CLONE
- newExtension.asAssemblyName = (AssemblyName)asAssemblyName.Clone();
-#else
- newExtension.asAssemblyName = new AssemblyName(asAssemblyName.FullName);
-#endif
+ newExtension.asAssemblyName = asAssemblyName.CloneIfPossible();
}
newExtension.asString = asString;
diff --git a/src/Shared/AssemblyUtilities.cs b/src/Shared/AssemblyUtilities.cs
index a40a6d46268..51a8aae49ef 100644
--- a/src/Shared/AssemblyUtilities.cs
+++ b/src/Shared/AssemblyUtilities.cs
@@ -11,6 +11,13 @@ namespace Microsoft.Build.Shared
///
internal static class AssemblyUtilities
{
+ // True when the cached method info objects have been set.
+ private static bool s_initialized;
+
+ // Cached method info
+ private static MethodInfo s_assemblyNameCloneMethod;
+ private static PropertyInfo s_assemblylocationProperty;
+
public static string GetAssemblyLocation(Assembly assembly)
{
#if FEATURE_ASSEMBLY_LOCATION
@@ -18,15 +25,14 @@ public static string GetAssemblyLocation(Assembly assembly)
#else
// Assembly.Location is only available in .netstandard1.5, but MSBuild needs to target 1.3.
// use reflection to access the property
+ Initialize();
- var locationProperty = assembly.GetType().GetProperty("Location", typeof(string));
-
- if (locationProperty == null)
+ if (s_assemblylocationProperty == null)
{
throw new NotSupportedException("Type Assembly does not have the Location property");
}
- return (string)locationProperty.GetValue(assembly);
+ return (string)s_assemblylocationProperty.GetValue(assembly);
#endif
}
@@ -39,5 +45,37 @@ public static Type GetTypeInfo(this Type t)
return t;
}
#endif
+
+ public static AssemblyName CloneIfPossible(this AssemblyName assemblyNameToClone)
+ {
+#if FEATURE_ASSEMBLYNAME_CLONE
+ return (AssemblyName) assemblyNameToClone.Clone();
+#else
+
+ Initialize();
+
+ if (s_assemblyNameCloneMethod == null)
+ {
+ return new AssemblyName(assemblyNameToClone.FullName);
+ }
+
+ // Try to Invoke the Clone method via reflection. If the method exists (it will on .NET
+ // Core 2.0 or later) use that result, otherwise use new AssemblyName(FullName).
+ return (AssemblyName) s_assemblyNameCloneMethod.Invoke(assemblyNameToClone, null) ??
+ new AssemblyName(assemblyNameToClone.FullName);
+#endif
+ }
+
+ ///
+ /// Initialize static fields. Doesn't need to be thread safe.
+ ///
+ private static void Initialize()
+ {
+ if (s_initialized) return;
+
+ s_initialized = true;
+ s_assemblyNameCloneMethod = typeof(AssemblyName).GetMethod("Clone");
+ s_assemblylocationProperty = typeof(Assembly).GetProperty("Location", typeof(string));
+ }
}
}
diff --git a/src/Tasks/AppConfig/DependentAssembly.cs b/src/Tasks/AppConfig/DependentAssembly.cs
index 3c70399c50b..c7252c95b3f 100644
--- a/src/Tasks/AppConfig/DependentAssembly.cs
+++ b/src/Tasks/AppConfig/DependentAssembly.cs
@@ -22,35 +22,23 @@ internal sealed class DependentAssembly
private BindingRedirect[] _bindingRedirects = null;
///
- /// The partial assemblyname, there should be no version.
+ /// The partial , there should be no version.
///
- private AssemblyName _partialAssemblyName = null;
+ private AssemblyName _partialAssemblyName;
///
- /// The partial assemblyname, there should be no version.
+ /// The partial , there should be no version.
///
internal AssemblyName PartialAssemblyName
{
set
{
-#if FEATURE_ASSEMBLYNAME_CLONE
- _partialAssemblyName = (AssemblyName)value.Clone();
-#else
- _partialAssemblyName = new AssemblyName(value.FullName);
-#endif
+ _partialAssemblyName = value.CloneIfPossible();
_partialAssemblyName.Version = null;
}
get
{
- if (_partialAssemblyName == null)
- {
- return null;
- }
-#if FEATURE_ASSEMBLYNAME_CLONE
- return (AssemblyName)_partialAssemblyName.Clone();
-#else
- return new AssemblyName(_partialAssemblyName.FullName);
-#endif
+ return _partialAssemblyName?.CloneIfPossible();
}
}
diff --git a/src/Tasks/AssemblyDependency/ReferenceTable.cs b/src/Tasks/AssemblyDependency/ReferenceTable.cs
index cd4bbc230e3..e6082536856 100644
--- a/src/Tasks/AssemblyDependency/ReferenceTable.cs
+++ b/src/Tasks/AssemblyDependency/ReferenceTable.cs
@@ -1070,14 +1070,9 @@ IEnumerable preUnificationAssemblyNames
{
foreach (AssemblyNameExtension preUnificationAssemblyName in preUnificationAssemblyNames)
{
- string name = preUnificationAssemblyName.Name;
// First, unify the assembly name so that we're dealing with the right version.
// Not AssemblyNameExtension because we're going to write to it.
-#if FEATURE_ASSEMBLYNAME_CLONE
- AssemblyNameExtension dependentAssembly = new AssemblyNameExtension((AssemblyName)preUnificationAssemblyName.AssemblyName.Clone());
-#else
- AssemblyNameExtension dependentAssembly = new AssemblyNameExtension(new AssemblyName(preUnificationAssemblyName.AssemblyName.FullName));
-#endif
+ AssemblyNameExtension dependentAssembly = new AssemblyNameExtension(preUnificationAssemblyName.AssemblyName.CloneIfPossible());
Version unifiedVersion;
bool isPrerequisite;
@@ -1883,11 +1878,7 @@ out AssemblyNameReference[] conflictingReferences
byte[] pkt = assemblyName.GetPublicKeyToken();
if (pkt != null && pkt.Length > 0)
{
-#if FEATURE_ASSEMBLYNAME_CLONE
- AssemblyName baseKey = (AssemblyName)assemblyName.AssemblyName.Clone();
-#else
- AssemblyName baseKey = new AssemblyName(assemblyName.AssemblyName.FullName);
-#endif
+ AssemblyName baseKey = assemblyName.AssemblyName.CloneIfPossible();
Version version = baseKey.Version;
baseKey.Version = null;
string key = baseKey.ToString();
@@ -2377,11 +2368,7 @@ out string redistName
foreach (DependentAssembly remappedAssembly in _remappedAssemblies)
{
// First, exclude anything without the simple name match
-#if FEATURE_ASSEMBLYNAME_CLONE
- AssemblyNameExtension comparisonAssembly = new AssemblyNameExtension((AssemblyName)remappedAssembly.PartialAssemblyName.Clone());
-#else
- AssemblyNameExtension comparisonAssembly = new AssemblyNameExtension(new AssemblyName(remappedAssembly.PartialAssemblyName.FullName));
-#endif
+ AssemblyNameExtension comparisonAssembly = new AssemblyNameExtension(remappedAssembly.PartialAssemblyName.CloneIfPossible());
if (assemblyName.CompareBaseNameTo(comparisonAssembly) == 0)
{
// Comparison assembly is a partial name. Give it our version.