如何找到两种类型中最小的可分配类型(重复)?

Ken*_*Kin 13 c# reflection types

这是两种使用的扩展方法

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
}
Run Code Online (Sandbox Code Playgroud)
  • FindInterfaceWith返回null如果他们没有共同实现的接口.
  • FindBaseClassWith返回System.Object,如果他们有没有更多的衍生物共同的基类.
  • FindBaseClassWithnull如果其中一个参数是一个接口,则返回
  • null如果有任何参数,它们都会返回null.

最终解决方案中的方法签名如下:

public static Type FindAssignableWith(this Type type1, Type type2) {
    // what should be here?
}
Run Code Online (Sandbox Code Playgroud)

反射和Linq仅限使用,除非没有其他方法.

有没有好的方法之间找到共同类型的最适合type1type2

或者有更好的事情来实现这一目标吗?


更新:

根据我个人的理解,由于能够使用类实现多个接口,FindInterfaceWith可能需要在FindBaseClassWith内部调用; 否则最好的选择类型将是不可判定的.

如果这个假设是正确的,那么FindInterfaceWith它就变成了一个冗余的方法; 因为之间的唯一区别的FindInterfaceWithFindAssignableWith是:

FindInterfaceWithnull如果有最好的选择,则返回; while FindAssignableWith直接返回确切的类.

否则,它们都会返回最佳的界面选择.

这是关于说最初的假设是不合理的.也就是说,FindInterfaceWith如果FindAssignableWith不是,则无法实施.

Aki*_*kim 10

这是我的实现:

FindAssignableWith,FindBaseClassWithFindInterfaceWith实现

// 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);
}
Run Code Online (Sandbox Code Playgroud)

关于FindInterfaceWith实施的评论

在其他人之前实现IEnumerableIEnumerable<T>将被选择的任何接口,我认为不正确

开放式问题 FindInterfaceWith

允许在一个类中实现多个接口,在这种情况下,第一个接口将被返回FindInterfaceWith,因为在以下示例中通常无法知道哪个接口IAIB更优选

multiple_interfaces_implementing

接口和类层次结构

    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 {}
Run Code Online (Sandbox Code Playgroud)

测试用例

使用NUnit断言的一组测试用例:

FindBaseClassWith 断言的例子

// 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)));
Run Code Online (Sandbox Code Playgroud)

FindInterfaceWith 断言的例子

// 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)));
Run Code Online (Sandbox Code Playgroud)

FinAssignableWith 断言的例子

Assert.That(typeof(DeriviedLeft).FindAssignableWith(typeof(DeriviedLeft)), Is.SameAs(typeof(DeriviedLeft)));
Run Code Online (Sandbox Code Playgroud)

在CodeReview上讨论

回顾这个答案 codereview.stackexchange.com

ps:
完整资源[ 这里 ]

  • 对不起,我的私人电报现在是寒假,因此提供了"最合适的"的确切定义.在有可能设计实现多个接口的类之前,您无法解决此问题.我的建议,`FindEqualTypeWith`应返回几种最佳类型,即枚举类型而不是一种类型.在原始答案中查看"FindInterfaceWith"的未解决问题. (2认同)