Remove Microsoft.Extensions.ClosedGenericMatcher.Sources

This code isn't used locally, so it will move to aspnet/AspNetCore
\n\nCommit migrated from 7305817fea
This commit is contained in:
Nate McMaster 2018-12-13 11:01:34 -08:00
parent e8d84a1962
commit 2f36a1ecf9
2 changed files with 0 additions and 466 deletions

View File

@ -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
{
/// <summary>
/// Helper related to generic interface definitions and implementing classes.
/// </summary>
internal static class ClosedGenericMatcher
{
/// <summary>
/// Determine whether <paramref name="queryType"/> is or implements a closed generic <see cref="Type"/>
/// created from <paramref name="interfaceType"/>.
/// </summary>
/// <param name="queryType">The <see cref="Type"/> of interest.</param>
/// <param name="interfaceType">The open generic <see cref="Type"/> to match. Usually an interface.</param>
/// <returns>
/// The closed generic <see cref="Type"/> created from <paramref name="interfaceType"/> that
/// <paramref name="queryType"/> is or implements. <c>null</c> if the two <see cref="Type"/>s have no such
/// relationship.
/// </returns>
/// <remarks>
/// This method will return <paramref name="queryType"/> if <paramref name="interfaceType"/> is
/// <c>typeof(KeyValuePair{,})</c>, and <paramref name="queryType"/> is
/// <c>typeof(KeyValuePair{string, object})</c>.
/// </remarks>
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);
}
}
}
}

View File

@ -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<Type, Type, Type> ExtractGenericInterfaceDataSet
{
get
{
return new TheoryData<Type, Type, Type>
{
// Closed generic types that match given open generic type.
{
typeof(IEnumerable<BaseClass>),
typeof(IEnumerable<>),
typeof(IEnumerable<BaseClass>)
},
{
typeof(IReadOnlyList<int>),
typeof(IReadOnlyList<>),
typeof(IReadOnlyList<int>)
},
{
typeof(KeyValuePair<string, object>),
typeof(KeyValuePair<,>),
typeof(KeyValuePair<string, object>)
},
// Closed generic interfaces that implement sub-interface of given open generic type.
{
typeof(ICollection<BaseClass>),
typeof(IEnumerable<>),
typeof(IEnumerable<BaseClass>)
},
{
typeof(IReadOnlyList<int>),
typeof(IEnumerable<>),
typeof(IEnumerable<int>)
},
{
typeof(IDictionary<string, object>),
typeof(IEnumerable<>),
typeof(IEnumerable<KeyValuePair<string, object>>)
},
// Class that implements closed generic based on given open generic interface.
{
typeof(BaseClass),
typeof(IDictionary<,>),
typeof(IDictionary<string, object>)
},
{
typeof(BaseClass),
typeof(IEquatable<>),
typeof(IEquatable<BaseClass>)
},
{
typeof(BaseClass),
typeof(ICollection<>),
typeof(ICollection<KeyValuePair<string, object>>)
},
// Derived class that implements closed generic based on given open generic interface.
{
typeof(DerivedClass),
typeof(IDictionary<,>),
typeof(IDictionary<string, object>)
},
{
typeof(DerivedClass),
typeof(IEquatable<>),
typeof(IEquatable<BaseClass>)
},
{
typeof(DerivedClass),
typeof(ICollection<>),
typeof(ICollection<KeyValuePair<string, object>>)
},
// Derived class that also implements another interface.
{
typeof(DerivedClassWithComparable),
typeof(IDictionary<,>),
typeof(IDictionary<string, object>)
},
{
typeof(DerivedClassWithComparable),
typeof(IEquatable<>),
typeof(IEquatable<BaseClass>)
},
{
typeof(DerivedClassWithComparable),
typeof(ICollection<>),
typeof(ICollection<KeyValuePair<string, object>>)
},
{
typeof(DerivedClassWithComparable),
typeof(IComparable<>),
typeof(IComparable<DerivedClassWithComparable>)
},
// Derived class using system implementation.
{
typeof(DerivedClassFromSystemImplementation),
typeof(ICollection<>),
typeof(ICollection<BaseClass>)
},
{
typeof(DerivedClassFromSystemImplementation),
typeof(IReadOnlyList<>),
typeof(IReadOnlyList<BaseClass>)
},
{
typeof(DerivedClassFromSystemImplementation),
typeof(IEnumerable<>),
typeof(IEnumerable<BaseClass>)
},
// Not given an open generic type.
{
typeof(IEnumerable<BaseClass>),
typeof(IEnumerable<BaseClass>),
null
},
{
typeof(IEnumerable<BaseClass>),
typeof(IEnumerable),
null
},
{
typeof(IReadOnlyList<int>),
typeof(BaseClass),
null
},
{
typeof(KeyValuePair<,>),
typeof(KeyValuePair<string, object>),
null
},
// Not a match.
{
typeof(IEnumerable<BaseClass>),
typeof(IReadOnlyList<>),
null
},
{
typeof(IList<int>),
typeof(IReadOnlyList<>),
null
},
{
typeof(IDictionary<string, object>),
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<int> 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<int>), result);
}
// IEnumerable<int> 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<int>), result);
}
private class TwoIEnumerableImplementationsOnSameClass : IEnumerable<string>, IEnumerable<int>
{
IEnumerator<int> IEnumerable<int>.GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator<string> IEnumerable<string>.GetEnumerator()
{
throw new NotImplementedException();
}
}
private class TwoIEnumerableImplementationsInherited : List<int>, IEnumerable<string>
{
IEnumerator<string> IEnumerable<string>.GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}
private class BaseClass : IDictionary<string, object>, IEquatable<BaseClass>
{
object IDictionary<string, object>.this[string key]
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
int ICollection<KeyValuePair<string, object>>.Count
{
get
{
throw new NotImplementedException();
}
}
bool ICollection<KeyValuePair<string, object>>.IsReadOnly
{
get
{
throw new NotImplementedException();
}
}
ICollection<string> IDictionary<string, object>.Keys
{
get
{
throw new NotImplementedException();
}
}
ICollection<object> IDictionary<string, object>.Values
{
get
{
throw new NotImplementedException();
}
}
public bool Equals(BaseClass other)
{
throw new NotImplementedException();
}
void ICollection<KeyValuePair<string, object>>.Add(KeyValuePair<string, object> item)
{
throw new NotImplementedException();
}
void IDictionary<string, object>.Add(string key, object value)
{
throw new NotImplementedException();
}
void ICollection<KeyValuePair<string, object>>.Clear()
{
throw new NotImplementedException();
}
bool ICollection<KeyValuePair<string, object>>.Contains(KeyValuePair<string, object> item)
{
throw new NotImplementedException();
}
bool IDictionary<string, object>.ContainsKey(string key)
{
throw new NotImplementedException();
}
void ICollection<KeyValuePair<string, object>>.CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator<KeyValuePair<string, object>> IEnumerable<KeyValuePair<string, object>>.GetEnumerator()
{
throw new NotImplementedException();
}
bool ICollection<KeyValuePair<string, object>>.Remove(KeyValuePair<string, object> item)
{
throw new NotImplementedException();
}
bool IDictionary<string, object>.Remove(string key)
{
throw new NotImplementedException();
}
bool IDictionary<string, object>.TryGetValue(string key, out object value)
{
throw new NotImplementedException();
}
}
private class DerivedClass : BaseClass
{
}
private class DerivedClassWithComparable : DerivedClass, IComparable<DerivedClassWithComparable>
{
public int CompareTo(DerivedClassWithComparable other)
{
throw new NotImplementedException();
}
}
private class DerivedClassFromSystemImplementation : Collection<BaseClass>
{
}
}
}