如何找到两个类型之间常见的一种类型最适合? [英] How to find the best fit of common type between two types?

查看:127
本文介绍了如何找到两个类型之间常见的一种类型最适合?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Here're使用两个扩展方法

 公共静态类型FindInterfaceWith(这种类型的1型,2型型){
//返回最适合普通实现的接口
}

公共静态类型FindBaseClassWith(这种类型的1型,2型型){
//返回最衍生公共基类的
}




  • FindInterfaceWith 收益,如果他们没有共同实现的接口。

  • FindBaseClassWith 收益 System.Object的,如果他们没有更衍生物共同的基类。

  • FindBaseClassWith 收益如果参数之一是一个接口。

  • 这两个他们返回如果任何参数是



和方法的签名在最后的解决办法是这样的:

 公共静态类型FindEqualTypeWith(这种类型的1型,2型型){
//应该是什么吗?
}



反思和LINQ被限制使用,除非有没有其他方法



有没有好的方法可以找到常见的一种类型 1型之间的最佳匹配 2型



还是有更好的东西来实现这一目标?






更新#1



< 据@Akim的答案,我终于张贴在Q&放大器解决方案; A形式








更新#0:



这是我个人的理解,因为在 应用于实现多个接口的能力一类,在 FindInterfaceWith 可能需要了 FindBaseClassWith 内部调用;否则型的最佳选择将是不可判定的。



如果这一假设是正确的,那么 FindInterfaceWith 变得冗余的方法;因为之间的唯一区别的 FindInterfaceWith FindEqualTypeWith 是:



FindInterfaceWith 收益如果有类的最佳选择;而 FindEqualTypeWith 直接返回准确的类。



否则,他们都返回接口的最佳选择。



这是有关说法最初的假设是不合理的。也就是说, FindInterfaceWith 无法执行,如果 FindEqualTypeWith 。这将推断,任何当前现有的实现 FindInterfaceWith 的,包括我的。


解决方案

下面是我实现的:



FindEqualTypeWith FindBaseClassWith FindInterfaceWith 实施



  //提供公共基类或实现的接口
公共静态类型FindEqualTypeWith(这种类型typeLeft,键入typeRight)
{
如果( typeLeft == NULL || typeRight == NULL)返回NULL;

VAR commonBaseClass = typeLeft.FindBaseClassWith(typeRight)? typeof运算(对象);

返回commonBaseClass.Equals(typeof运算(对象))
? typeLeft.FindInterfaceWith(typeRight)
:commonBaseClass;
}

//寻找共同的基类(或具体或抽象)
公共静态类型FindBaseClassWith(这种类型typeLeft,键入typeRight)
{
如果(typeLeft == NULL || typeRight == NULL)返回NULL;

返回typeLeft
.GetClassHierarchy()
.Intersect(typeRight.GetClassHierarchy())
.FirstOrDefault(类型=>!type.IsInterface);
}

//寻找共同实现的接口
//有可能为一个类实现多个接口,
//在这种情况下返回第一个基于通用接口
公共静态类型FindInterfaceWith(这种类型typeLeft,键入typeRight)
{
如果(typeLeft == NULL || typeRight == NULL)返回NULL;

返回typeLeft
.GetInterfaceHierarchy()
.Intersect(typeRight.GetInterfaceHierarchy())
.FirstOrDefault();
}

//遍历接口hierarhy
公共静态的IEnumerable<类型> GetInterfaceHierarchy(这种类型)
{
如果(type.IsInterface)返回新的[] {}型.AsEnumerable();

返回类型
.GetInterfaces()
.OrderByDescending(电流=> current.GetInterfaces()计数()。)
.AsEnumerable();
}

//阶级hierarhy
公共静态的IEnumerable< interate;类型> GetClassHierarchy(这种类型)
{
如果(类型== NULL)产量突破;

型typeInHierarchy =类型;


{
收益率的回报typeInHierarchy;
typeInHierarchy = typeInHierarchy.BaseType;
}
,而(typeInHierarchy = NULL&放大器;!&安培;!typeInHierarchy.IsInterface);
}



关于备注 FindInterfaceWith 实施



这是实现任何接口或者的IEnumerable 的IEnumerable< T> 将别人,有什么我认为不正确



<的H3>开放式问题 FindInterfaceWith

C#的允许多个接口在一个类中实现,在这种情况下,接口第一个将被 FindInterfaceWith ,,因为没有办法怎么知道哪个接口 IA IB 表现一般最好在下面的示例





的接口和类层次结构



 公共接口IBase的{} 
公共接口ISomething {}
公共接口IDerivied:IBase的{}
公共接口IDeriviedRight:IDerivied {}
公共接口IDeriviedLeft:IDerivied,IDisposable的{}

公共类AnotherDisposable:IDisposable接口{
公共无效的Dispose(){
}
}

公共类DeriviedLeft:IDeriviedLeft {
公共无效的Dispose(){
}
}

公共类SubDeriviedLeft:DeriviedLeft {}
公共类SecondSubDeriviedLeft:DeriviedLeft {}
公共类ThirdSubDeriviedLeft:DeriviedLeft,ISomething {}

公共类另一个{}
公共类DeriviedRight:IDeriviedRight {}



测试用例



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



FindBaseClassWith 断言例如

  // FindBaseClassWith返回null如果参数中的一个是一个接口。 
// FindBaseClassWith返回null如果任何参数为空。
Assert.That(typeof运算(DeriviedLeft).FindBaseClassWith(typeof运算(DeriviedLeft)),Is.EqualTo(typeof运算(DeriviedLeft)));



FindInterfaceWith 断言例如

  // FindInterfaceWith如果他们没有共同实现的接口返回null。 
// FindBaseClassWith返回null如果任何参数为空。
Assert.That(typeof运算(DeriviedLeft).FindInterfaceWith(typeof运算(DeriviedLeft)),Is.EqualTo(typeof运算(IDeriviedLeft)));



FindEqualTypeWith 断言例如

  Assert.That(typeof运算(DeriviedLeft).FindEqualTypeWith(typeof运算(DeriviedLeft)),Is.SameAs(typeof运算(DeriviedLeft))); 



作者在代码审查



codereview.stackexchange.com

PS

全源可用[的这里]


Here're two extension methods for use

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 returns null if they don't have common implemented interface.
  • FindBaseClassWith returns System.Object if they have no more derivative common base class.
  • FindBaseClassWith returns null if one of parameters was an interface.
  • Both they return null if any of parameter was null.

And the signature of method in finally solution would be like:

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

Reflection and Linq are restricted to use, except there are no other ways.

Are there good ways to find the best fit of common type between type1 and type2?

Or are there something better to achieve this?


update #1:

According to the answer of @Akim, I finally posted a solution in a Q&A form


update #0:

By my personal understanding, because of the ability to implement multiple interfaces with a class, the FindInterfaceWith could possibly need to call FindBaseClassWith internally; otherwise the best choice of type would be undecidable.

If this supposition was correct, then the FindInterfaceWith becomes a redundant method; because of the only difference between FindInterfaceWith and FindEqualTypeWith is:

FindInterfaceWith returns null if there was a best choice of class; while FindEqualTypeWith returns the exact class directly.

Otherwise, they both return a best choice of interface.

This is about saying the original assumption was irrational. That is, FindInterfaceWith cannot be implemented if FindEqualTypeWith is not. This would infer that any of current existing implementation of FindInterfaceWith including mine.

解决方案

Here is my implementation:

FindEqualTypeWith, FindBaseClassWith and FindInterfaceWith implementations

// provide common base class or implemented interface
public static Type FindEqualTypeWith(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);
}

Remark regarding FindInterfaceWith implementation

Any interfaces that implements either IEnumerable or IEnumerable<T> will be selected before others, what I considered not to be correct

Open ended question of FindInterfaceWith

allow multiple interfaces to be implemented in one class, in this case first one of interfaces will be returned by FindInterfaceWith, because there is no way how to know which of interfaces IA or IB are preferable in general in following sample

Interfaces and classes hierarchy

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

Test cases

And set of test cases using NUnit assertions:

FindBaseClassWith assertions example

// 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 assertions example

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

FindEqualTypeWith assertions example

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

Discussion at CodeReview

Review of this answer at codereview.stackexchange.com

ps:
Full sources available [here]

这篇关于如何找到两个类型之间常见的一种类型最适合?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆