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:
parent
e8d84a1962
commit
2f36a1ecf9
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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>
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue