这个问题已经有了答案:
How to find the minimum covariant type for best fit between two types?
3答
这里有两种扩展方法
public static Type FindInterfaceWith(this Type type1, Type type2) {
// returns most suitable common implemented interface
}
public static Type FindBaseClassWith(this Type type1, Type type2) {
// returns most derivative of common base class
}
FindInterfaceWith
如果它们没有公共实现接口,则返回null
。FindBaseClassWith
如果它们没有更多的派生公共基类,则返回System.Object
。FindBaseClassWith
返回null
如果其中一个参数是接口。如果参数为“cc>”,它们都返回
null
。最终解中方法的签名如下:
public static Type FindAssignableWith(this Type type1, Type type2) {
// what should be here?
}
反射和LINQ仅限于使用,除非没有其他方法。
在
null
和type1
之间找到最适合普通类型的方法吗?或者有更好的办法来实现这个目标吗?
更新:
根据我个人的理解,由于可以用一个类实现多个接口,
type2
可能需要在内部调用FindInterfaceWith
,否则最好的类型选择是不确定的。如果这个假设是正确的,那么
FindBaseClassWith
成为冗余方法;因为FindInterfaceWith
和FindInterfaceWith
之间唯一的区别是:FindAssignableWith
返回FindInterfaceWith
如果有一个最好的类选择;而null
直接返回确切的类。否则,它们都会返回一个最佳的接口选择。
这是说原来的假设是不合理的。也就是说,如果
FindAssignableWith
不是,则无法实现FindInterfaceWith
。 最佳答案
以下是我的实现:FindAssignableWith
、FindBaseClassWith
和FindInterfaceWith
实现
// provide common base class or implemented interface
public static Type FindAssignableWith(this Type typeLeft, Type typeRight)
{
if(typeLeft == null || typeRight == null) return null;
var commonBaseClass = typeLeft.FindBaseClassWith(typeRight) ?? typeof(object);
return commonBaseClass.Equals(typeof(object))
? typeLeft.FindInterfaceWith(typeRight)
: commonBaseClass;
}
// searching for common base class (either concrete or abstract)
public static Type FindBaseClassWith(this Type typeLeft, Type typeRight)
{
if(typeLeft == null || typeRight == null) return null;
return typeLeft
.GetClassHierarchy()
.Intersect(typeRight.GetClassHierarchy())
.FirstOrDefault(type => !type.IsInterface);
}
// searching for common implemented interface
// it's possible for one class to implement multiple interfaces,
// in this case return first common based interface
public static Type FindInterfaceWith(this Type typeLeft, Type typeRight)
{
if(typeLeft == null || typeRight == null) return null;
return typeLeft
.GetInterfaceHierarchy()
.Intersect(typeRight.GetInterfaceHierarchy())
.FirstOrDefault();
}
// iterate on interface hierarhy
public static IEnumerable<Type> GetInterfaceHierarchy(this Type type)
{
if(type.IsInterface) return new [] { type }.AsEnumerable();
return type
.GetInterfaces()
.OrderByDescending(current => current.GetInterfaces().Count())
.AsEnumerable();
}
// interate on class hierarhy
public static IEnumerable<Type> GetClassHierarchy(this Type type)
{
if(type == null) yield break;
Type typeInHierarchy = type;
do
{
yield return typeInHierarchy;
typeInHierarchy = typeInHierarchy.BaseType;
}
while(typeInHierarchy != null && !typeInHierarchy.IsInterface);
}
关于
FindInterfaceWith
实施的备注任何实现
IEnumerable
或IEnumerable<T>
的接口都将在其他接口之前被选中,这是我认为不正确的FindInterfaceWith
的开放式问题c#允许在一个类中实现多个接口,在这种情况下,第一个接口将由
FindInterfaceWith
返回,因为在下面的示例中通常无法知道哪个接口更可取接口和类层次结构
public interface IBase {}
public interface ISomething {}
public interface IDerivied: IBase {}
public interface IDeriviedRight: IDerivied {}
public interface IDeriviedLeft: IDerivied, IDisposable {}
public class AnotherDisposable: IDisposable {
public void Dispose() {
}
}
public class DeriviedLeft: IDeriviedLeft {
public void Dispose() {
}
}
public class SubDeriviedLeft: DeriviedLeft {}
public class SecondSubDeriviedLeft: DeriviedLeft {}
public class ThirdSubDeriviedLeft: DeriviedLeft, ISomething {}
public class Another {}
public class DeriviedRight: IDeriviedRight {}
测试用例
以及一组使用
IA
断言的测试用例:IB
断言示例// FindBaseClassWith returns null if one of parameters was an interface.
// FindBaseClassWith return null if any of parameter was null.
Assert.That(typeof(DeriviedLeft).FindBaseClassWith(typeof(DeriviedLeft)), Is.EqualTo(typeof(DeriviedLeft)));
NUnit
断言示例// FindInterfaceWith returns null if they don't have common implemented interface.
// FindBaseClassWith return null if any of parameter was null.
Assert.That(typeof(DeriviedLeft).FindInterfaceWith(typeof(DeriviedLeft)), Is.EqualTo(typeof(IDeriviedLeft)));
FindBaseClassWith
断言示例Assert.That(typeof(DeriviedLeft).FindAssignableWith(typeof(DeriviedLeft)), Is.SameAs(typeof(DeriviedLeft)));
代码评审讨论
Review of this answer at
FindInterfaceWith
PS:
可用的完整源代码[here]
关于c# - 如何找到两种类型中的最小可分配类型(重复)? ,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/14107683/