这里有两种扩展方法可以使用
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是限制使用的,除了别无他法。
是否有好的方法可以找到type1
和type2
之间最适合的通用类型?
或者有什么更好的方法可以实现这一点?
更新:
根据我个人的理解,由于类能够实现多个接口(interface),FindInterfaceWith
可能需要调用 FindBaseClassWith
内部;否则类型的最佳选择将无法确定。
如果这个假设是正确的,那么 FindInterfaceWith
就变成了一个多余的方法;因为 FindInterfaceWith
和 FindAssignableWith
之间的唯一区别是:
FindInterfaceWith
如果有最佳类选择,则返回 null
;而 FindAssignableWith
直接返回确切的类。
否则,它们都返回最佳接口(interface)选择。
这是说最初的假设是不合理的。也就是说,如果 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
的接口(interface)或 IEnumerable<T>
将在其他人之前被选中,我认为不正确
FindInterfaceWith
的开放式问题
c#允许在一个类中实现多个接口(interface),在这种情况下,第一个接口(interface)将由 FindInterfaceWith
返回, 因为无法知道是哪个接口(interface) IA
或 IB
通常在以下示例中更可取
接口(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 ]