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

标签 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
}
  • FindInterfaceWith 如果它们没有共同实现的接口(interface),则返回 null
  • FindBaseClassWith 如果它们没有更多派生公共(public)基类,则返回 System.Object
  • FindBaseClassWith 如果参数之一是接口(interface),则返回 null
  • 如果任何参数为 null,它们都返回 null

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

public static Type FindAssignableWith(this Type type1, Type type2) {
    // what should be here?
}

Reflection和Linq是限制使用的,除了别无他法。

是否有好的方法可以找到type1type2 之间最适合的通用类型?

或者有什么更好的方法可以实现这一点?


更新:

根据我个人的理解,由于类能够实现多个接口(interface)FindInterfaceWith 可能需要调用 FindBaseClassWith 内部;否则类型的最佳选择将无法确定。

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

FindInterfaceWith 如果有最佳类选择,则返回 null;而 FindAssignableWith 直接返回确切的类。

否则,它们都返回最佳接口(interface)选择。

这是说最初的假设是不合理的。也就是说,如果 FindAssignableWith 不是,则无法实现 FindInterfaceWith

最佳答案

这是我的实现:

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);
}

关于FindInterfaceWith的备注实现

任何实现 IEnumerable 的接口(interface)或 IEnumerable<T>将在其他人之前被选中,我认为不正确

FindInterfaceWith 的开放式问题

允许在一个类中实现多个接口(interface),在这种情况下,第一个接口(interface)将由 FindInterfaceWith 返回, 因为无法知道是哪个接口(interface) IAIB通常在以下示例中更可取

multiple_interfaces_implementing

接口(interface)和类层次结构

    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 {}

测试用例

和一组使用 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)));

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)));

FinAssignableWith断言示例

Assert.That(typeof(DeriviedLeft).FindAssignableWith(typeof(DeriviedLeft)), Is.SameAs(typeof(DeriviedLeft)));

CodeReview 讨论

Review of this answer at codereview.stackexchange.com

附言:
提供完整资源 [ here ]

关于c# - 如何找到两种类型中最小的可分配类型(重复)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14107683/

相关文章:

c# - LINQ 查询根据匹配的另一个表从一个表返回

google-maps - 地理编码服务返回未捕获的类型错误 : #<Object> object has no method 'apply'

java - 找出构造了哪个枚举值

java - 使用 entityClass.newInstance() 创建的实例上的 invokeExact 导致 java.lang.invoke.WrongMethodTypeException?

go - 如何查找类型是否为 float64

go - 这是在 golang 中类型转换的吗?

c# - FluentValidation 可以处理嵌套集合吗?

c# - Xamarin.Forms 和 MVVM 在 C# : PropertyChanged Event Handler Is Always Null When OnPropertyChanged Called

c# - 将 foreach 循环中发生的条件作为参数传递

function - 如何在 Rust 中找到函数调用者的类型?