这个问题已经有了答案:
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仅限于使用,除非没有其他方法。
nulltype1之间找到最适合普通类型的方法吗?
或者有更好的办法来实现这个目标吗?
更新:
根据我个人的理解,由于可以用一个类实现多个接口,type2可能需要在内部调用FindInterfaceWith,否则最好的类型选择是不确定的。
如果这个假设是正确的,那么FindBaseClassWith成为冗余方法;因为FindInterfaceWithFindInterfaceWith之间唯一的区别是:
FindAssignableWith返回FindInterfaceWith如果有一个最好的类选择;而null直接返回确切的类。
否则,它们都会返回一个最佳的接口选择。
这是说原来的假设是不合理的。也就是说,如果FindAssignableWith不是,则无法实现FindInterfaceWith

最佳答案

以下是我的实现:
FindAssignableWithFindBaseClassWithFindInterfaceWith实现

// 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实施的备注
任何实现IEnumerableIEnumerable<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/

10-09 04:54