diff --git a/src/Shared/ClosedGenericMatcher/ClosedGenericMatcher.cs b/src/Shared/ClosedGenericMatcher/ClosedGenericMatcher.cs deleted file mode 100644 index f234c2edbc..0000000000 --- a/src/Shared/ClosedGenericMatcher/ClosedGenericMatcher.cs +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Linq; -using System.Reflection; - -namespace Microsoft.Extensions.Internal -{ - /// - /// Helper related to generic interface definitions and implementing classes. - /// - internal static class ClosedGenericMatcher - { - /// - /// Determine whether is or implements a closed generic - /// created from . - /// - /// The of interest. - /// The open generic to match. Usually an interface. - /// - /// The closed generic created from that - /// is or implements. null if the two s have no such - /// relationship. - /// - /// - /// This method will return if is - /// typeof(KeyValuePair{,}), and is - /// typeof(KeyValuePair{string, object}). - /// - public static Type ExtractGenericInterface(Type queryType, Type interfaceType) - { - if (queryType == null) - { - throw new ArgumentNullException(nameof(queryType)); - } - - if (interfaceType == null) - { - throw new ArgumentNullException(nameof(interfaceType)); - } - - if (IsGenericInstantiation(queryType, interfaceType)) - { - // queryType matches (i.e. is a closed generic type created from) the open generic type. - return queryType; - } - - // Otherwise check all interfaces the type implements for a match. - // - If multiple different generic instantiations exists, we want the most derived one. - // - If that doesn't break the tie, then we sort alphabetically so that it's deterministic. - // - // We do this by looking at interfaces on the type, and recursing to the base type - // if we don't find any matches. - return GetGenericInstantiation(queryType, interfaceType); - } - - private static bool IsGenericInstantiation(Type candidate, Type interfaceType) - { - return - candidate.GetTypeInfo().IsGenericType && - candidate.GetGenericTypeDefinition() == interfaceType; - } - - private static Type GetGenericInstantiation(Type queryType, Type interfaceType) - { - Type bestMatch = null; - var interfaces = queryType.GetInterfaces(); - foreach (var @interface in interfaces) - { - if (IsGenericInstantiation(@interface, interfaceType)) - { - if (bestMatch == null) - { - bestMatch = @interface; - } - else if (StringComparer.Ordinal.Compare(@interface.FullName, bestMatch.FullName) < 0) - { - bestMatch = @interface; - } - else - { - // There are two matches at this level of the class hierarchy, but @interface is after - // bestMatch in the sort order. - } - } - } - - if (bestMatch != null) - { - return bestMatch; - } - - // BaseType will be null for object and interfaces, which means we've reached 'bottom'. - var baseType = queryType?.GetTypeInfo().BaseType; - if (baseType == null) - { - return null; - } - else - { - return GetGenericInstantiation(baseType, interfaceType); - } - } - } -} \ No newline at end of file diff --git a/src/Shared/test/Shared.Tests/ClosedGenericMatcherTest.cs b/src/Shared/test/Shared.Tests/ClosedGenericMatcherTest.cs deleted file mode 100644 index e71a792692..0000000000 --- a/src/Shared/test/Shared.Tests/ClosedGenericMatcherTest.cs +++ /dev/null @@ -1,360 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using Xunit; - -namespace Microsoft.Extensions.Internal -{ - public class ClosedGenericMatcherTest - { - // queryType, interfaceType, expectedResult - public static TheoryData ExtractGenericInterfaceDataSet - { - get - { - return new TheoryData - { - // Closed generic types that match given open generic type. - { - typeof(IEnumerable), - typeof(IEnumerable<>), - typeof(IEnumerable) - }, - { - typeof(IReadOnlyList), - typeof(IReadOnlyList<>), - typeof(IReadOnlyList) - }, - { - typeof(KeyValuePair), - typeof(KeyValuePair<,>), - typeof(KeyValuePair) - }, - // Closed generic interfaces that implement sub-interface of given open generic type. - { - typeof(ICollection), - typeof(IEnumerable<>), - typeof(IEnumerable) - }, - { - typeof(IReadOnlyList), - typeof(IEnumerable<>), - typeof(IEnumerable) - }, - { - typeof(IDictionary), - typeof(IEnumerable<>), - typeof(IEnumerable>) - }, - // Class that implements closed generic based on given open generic interface. - { - typeof(BaseClass), - typeof(IDictionary<,>), - typeof(IDictionary) - }, - { - typeof(BaseClass), - typeof(IEquatable<>), - typeof(IEquatable) - }, - { - typeof(BaseClass), - typeof(ICollection<>), - typeof(ICollection>) - }, - // Derived class that implements closed generic based on given open generic interface. - { - typeof(DerivedClass), - typeof(IDictionary<,>), - typeof(IDictionary) - }, - { - typeof(DerivedClass), - typeof(IEquatable<>), - typeof(IEquatable) - }, - { - typeof(DerivedClass), - typeof(ICollection<>), - typeof(ICollection>) - }, - // Derived class that also implements another interface. - { - typeof(DerivedClassWithComparable), - typeof(IDictionary<,>), - typeof(IDictionary) - }, - { - typeof(DerivedClassWithComparable), - typeof(IEquatable<>), - typeof(IEquatable) - }, - { - typeof(DerivedClassWithComparable), - typeof(ICollection<>), - typeof(ICollection>) - }, - { - typeof(DerivedClassWithComparable), - typeof(IComparable<>), - typeof(IComparable) - }, - // Derived class using system implementation. - { - typeof(DerivedClassFromSystemImplementation), - typeof(ICollection<>), - typeof(ICollection) - }, - { - typeof(DerivedClassFromSystemImplementation), - typeof(IReadOnlyList<>), - typeof(IReadOnlyList) - }, - { - typeof(DerivedClassFromSystemImplementation), - typeof(IEnumerable<>), - typeof(IEnumerable) - }, - // Not given an open generic type. - { - typeof(IEnumerable), - typeof(IEnumerable), - null - }, - { - typeof(IEnumerable), - typeof(IEnumerable), - null - }, - { - typeof(IReadOnlyList), - typeof(BaseClass), - null - }, - { - typeof(KeyValuePair<,>), - typeof(KeyValuePair), - null - }, - // Not a match. - { - typeof(IEnumerable), - typeof(IReadOnlyList<>), - null - }, - { - typeof(IList), - typeof(IReadOnlyList<>), - null - }, - { - typeof(IDictionary), - typeof(KeyValuePair<,>), - null - }, - }; - } - } - - [Theory] - [MemberData(nameof(ExtractGenericInterfaceDataSet))] - public void ExtractGenericInterface_ReturnsExpectedType( - Type queryType, - Type interfaceType, - Type expectedResult) - { - // Arrange & Act - var result = ClosedGenericMatcher.ExtractGenericInterface(queryType, interfaceType); - - // Assert - Assert.Equal(expectedResult, result); - } - - // IEnumerable is preferred because it is defined on the more-derived type. - [Fact] - public void ExtractGenericInterface_MultipleDefinitionsInherited() - { - // Arrange - var type = typeof(TwoIEnumerableImplementationsInherited); - - // Act - var result = ClosedGenericMatcher.ExtractGenericInterface(type, typeof(IEnumerable<>)); - - // Sort - Assert.Equal(typeof(IEnumerable), result); - } - - // IEnumerable is preferred because we sort by Ordinal on the full name. - [Fact] - public void ExtractGenericInterface_MultipleDefinitionsOnSameType() - { - // Arrange - var type = typeof(TwoIEnumerableImplementationsOnSameClass); - - // Act - var result = ClosedGenericMatcher.ExtractGenericInterface(type, typeof(IEnumerable<>)); - - // Sort - Assert.Equal(typeof(IEnumerable), result); - } - - private class TwoIEnumerableImplementationsOnSameClass : IEnumerable, IEnumerable - { - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotImplementedException(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotImplementedException(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotImplementedException(); - } - } - - private class TwoIEnumerableImplementationsInherited : List, IEnumerable - { - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotImplementedException(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotImplementedException(); - } - } - - private class BaseClass : IDictionary, IEquatable - { - object IDictionary.this[string key] - { - get - { - throw new NotImplementedException(); - } - - set - { - throw new NotImplementedException(); - } - } - - int ICollection>.Count - { - get - { - throw new NotImplementedException(); - } - } - - bool ICollection>.IsReadOnly - { - get - { - throw new NotImplementedException(); - } - } - - ICollection IDictionary.Keys - { - get - { - throw new NotImplementedException(); - } - } - - ICollection IDictionary.Values - { - get - { - throw new NotImplementedException(); - } - } - - public bool Equals(BaseClass other) - { - throw new NotImplementedException(); - } - - void ICollection>.Add(KeyValuePair item) - { - throw new NotImplementedException(); - } - - void IDictionary.Add(string key, object value) - { - throw new NotImplementedException(); - } - - void ICollection>.Clear() - { - throw new NotImplementedException(); - } - - bool ICollection>.Contains(KeyValuePair item) - { - throw new NotImplementedException(); - } - - bool IDictionary.ContainsKey(string key) - { - throw new NotImplementedException(); - } - - void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) - { - throw new NotImplementedException(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotImplementedException(); - } - - IEnumerator> IEnumerable>.GetEnumerator() - { - throw new NotImplementedException(); - } - - bool ICollection>.Remove(KeyValuePair item) - { - throw new NotImplementedException(); - } - - bool IDictionary.Remove(string key) - { - throw new NotImplementedException(); - } - - bool IDictionary.TryGetValue(string key, out object value) - { - throw new NotImplementedException(); - } - } - - private class DerivedClass : BaseClass - { - } - - private class DerivedClassWithComparable : DerivedClass, IComparable - { - public int CompareTo(DerivedClassWithComparable other) - { - throw new NotImplementedException(); - } - } - - private class DerivedClassFromSystemImplementation : Collection - { - } - } -} \ No newline at end of file