| File: System\Xaml\RefOnly\LooseTypeExtensions.cs | Web Access |
| Project: src\wpf\src\Microsoft.DotNet.Wpf\src\System.Xaml\System.Xaml.csproj (System.Xaml) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. #nullable disable using System.Reflection; using System.Windows.Markup; namespace System.Xaml { internal static class LooseTypeExtensions { private const string WindowsBase = "WindowsBase"; private static readonly byte[] WindowsBaseToken = { 49, 191, 56, 86, 173, 54, 78, 53 }; // Note: this is a version-tolerant comparison, i.e. the types are considered equal if their // names, namespaces, assembly short names, culture infos, and public keys match. internal static bool AssemblyQualifiedNameEquals(Type t1, Type t2) { if (t1 is null) { return t2 is null; } if (t2 is null) { return false; } if (t1.FullName != t2.FullName) { return false; } if (t1.Assembly.FullName == t2.Assembly.FullName) { return true; } AssemblyName t1name = new AssemblyName(t1.Assembly.FullName); AssemblyName t2name = new AssemblyName(t2.Assembly.FullName); if (t1name.Name == t2name.Name) { return t1name.CultureInfo.Equals(t2name.CultureInfo) && SafeSecurityHelper.IsSameKeyToken(t1name.GetPublicKeyToken(), t2name.GetPublicKeyToken()); } return IsWindowsBaseToSystemXamlComparison(t1.Assembly, t2.Assembly, t1name, t2name); } // When doing a version-tolerant comparison against System.Xaml types, we also need to // support references to types that were type-forwarded from WindowsBase. private static bool IsWindowsBaseToSystemXamlComparison(Assembly a1, Assembly a2, AssemblyName name1, AssemblyName name2) { AssemblyName windowsBaseName = null; if (name1.Name == WindowsBase && a2 == typeof(MarkupExtension).Assembly) { windowsBaseName = name1; } else if (name2.Name == WindowsBase && a1 == typeof(MarkupExtension).Assembly) { windowsBaseName = name2; } return (windowsBaseName is not null && SafeSecurityHelper.IsSameKeyToken(windowsBaseName.GetPublicKeyToken(), WindowsBaseToken)); } internal static bool IsAssemblyQualifiedNameAssignableFrom(Type t1, Type t2) { if (t1 is null || t2 is null) { return false; } if (AssemblyQualifiedNameEquals(t1, t2)) { return true; } if (IsLooseSubClassOf(t2, t1)) { return true; } if (t1.IsInterface) { return LooselyImplementInterface(t2, t1); } if (!t1.IsGenericParameter) { return false; } Type[] genericParameterConstraints = t1.GetGenericParameterConstraints(); for (int i = 0; i < genericParameterConstraints.Length; i++) { if (!IsAssemblyQualifiedNameAssignableFrom(genericParameterConstraints[i], t2)) { return false; } } return true; } private static bool LooselyImplementInterface(Type t, Type interfaceType) { for (Type type = t; type is not null; type = type.BaseType) { Type[] interfaces = type.GetInterfaces(); for (int i = 0; i < interfaces.Length; i++) { if (AssemblyQualifiedNameEquals(interfaces[i], interfaceType) || LooselyImplementInterface(interfaces[i], interfaceType)) { return true; } } } return false; } private static bool IsLooseSubClassOf(Type t1, Type t2) { if (t1 is null || t2 is null) { return false; } if (AssemblyQualifiedNameEquals(t1, t2)) { return false; // strictly testing for sub-class } for (Type baseType = t1.BaseType; baseType is not null; baseType = baseType.BaseType) { if (AssemblyQualifiedNameEquals(baseType, t2)) { return true; } } return false; } } }