问题 确定类是否实现了非常特定的接口


关于这个主题有很多问题,但我的版本略有改动。

我们有以下代码:

interface IFoo { }
interface IBar : IFoo { }
class Foo : IFoo { }
class Bar : IBar { }

bool Implements_IFoo(Type type) { /* ??? */ }

现在,故事的转折:方法 Implements_IFoo 应该只在Type实现IFoo而不是从IFoo派生的任何接口时返回true。这里举例说明此方法的一些示例:

Implements_IFoo(typeof(Foo)); // Should return true

Implements_IFoo(typeof(Bar)); // Should return false as Bar type 
                              // implements an interface derived from IFoo

请注意,可能有许多从IFoo派生的接口,您不一定知道它们的存在。

显而易见的方法是通过反射找到从IFoo派生的所有接口,然后只检查typeof(Bar).GetInterfaces()是其中的任何一个。但我想知道是否有人可以提出更优雅的解决方案。

PS问题源于我发现的一些代码使用这种检查(if(obj.GetType() == typeof(BaseClass)) { ... })。我们正在用特定代码的接口替换类。另外,以防万一 - 我将此检查作为布尔标志实现,所以这个问题纯粹是假设的。


8901
2018-04-27 13:29


起源

我真的好奇为什么你首先需要这种内省。机会是你的设计是错误的。 - tdammers
请在下次评论之前阅读问题“直到结束 - 我已经解释过这是一个假设的问题;) - Jefim


答案:


我试过了,因为它听起来很有趣,这适用于你的例子:

bool ImplementsIFooDirectly(Type t) {
    if (t.BaseType != null && ImplementsIFooDirectly(t.BaseType)) { 
        return false; 
    }
    foreach (var intf in t.GetInterfaces()) {
        if (ImplementsIFooDirectly(intf)) { 
            return false;
        }
    }
    return t.GetInterfaces().Any(i => i == typeof(IFoo));
}

结果:

ImplementsIFooDirectly(typeof(IFoo)); // false
ImplementsIFooDirectly(typeof(Bar)); // false
ImplementsIFooDirectly(typeof(Foo)); // true
ImplementsIFooDirectly(typeof(IBar)); // true

它不会查找从中派生的所有接口 IFoo,它只是传递继承/接口实现链,看看是否 IFoo 存在于除类型的确切级别之外的任何级别。

它还检测接口是否通过基类型继承。不确定这是不是你想要的。

尽管如此,正如其他人已经说过的那样,如果这对您来说真的是一个要求,那么您的设计可能会遇到问题。 (编辑:刚刚注意到你的问题纯粹是假设的。那当然没关系:))


9
2018-04-27 13:47



谢谢,这正是我的意思。将答案标记为正确,因为这是第一个正确答案。 :) - Jefim


有关如何实施此示例的示例,请参阅以下站点;

C#是关键字用法

本质上,您可以使用'is'关键字来确定对象是否作为类继承堆栈的一部分驻留在类类型中。

class Director  : Owner { }
class Developer : Employee { }
..
var dave = new Developer();
var steve = new Director();
var isEmployee = dave is Employee; // true
var isAlsoEmploye = steve is Employee; // false

符合您的示例功能:

bool Implements_Type(object instance, Type type) { 
return instance is type;
}

3
2018-04-27 13:40



我知道 is 关键字并没有解决问题。请参阅示例中的问题部分。请注意,IBar源自IFoo。因此Bar也通过IBar实现它。 is将为expr返回true。 Bar is IFoo 但这不是理想的结果。 - Jefim


static bool Implements_IFoo(Type type)
{
  if (typeof(IFoo).IsAssignableFrom(type.BaseType))
    return false;

  var barInterfaces = type.GetInterfaces()
    .Where(iface => typeof(IFoo).IsAssignableFrom(iface))
    .ToArray();

  return barInterfaces.Length > 0 
     && barInterfaces.Length == barInterfaces.Count(iface => iface == typeof(IFoo));
}
static bool Implements_IFoo_Optimized(Type type)
{
  if (typeof(IFoo).IsAssignableFrom(type.BaseType))
    return false;

  return type.GetInterfaces()
    .Where(iface => typeof(IFoo).IsAssignableFrom(iface))
    .Count() == 1;
}

2
2018-04-27 13:48



感谢你的回答!这正是我的意思。 - Jefim


这应该是诀窍:

 public bool ImplementsIFooOnly(Type type)
 {
     return !type.GetInterfaces().Any(t => 
              { 
                   return t is IFoo && !t.Equals(typeof(IFoo)); 
              });
 }

可能有更有效的方法。


1
2018-04-27 13:58



我猜你的意思 typeof(IFoo).IsAssignableFrom(t) 代替 t is IFoo,但是,这是东西:) - Jefim
以防万一 - 该代码不检查基类(嗯,我的问题中没有明确定义)和类型没有任何接口的条件(=> .Any(..) 然后返回false)。 - Jefim


您是否尝试使用该关键字? is

BTW一般来说,如果你有一个逻辑情况,某些类需要是某个基类的类型但不是某个继承者的类型,那么它可能是错误的OO设计,可能违反了 利斯科夫替代原则


0
2018-04-27 13:35



在一个 Type 目的? - mellamokb
再次, is 没有帮助,因为它会回来 true 为expr。 Bar is IFoo (并且所需的输出是 false 因为Bar通过'IBar'实现了IFoo。如果你想彻底阅读这个问题,你就不必费心去提Liskov和OO设计了。关键词:假设/理论。 ;) - Jefim


Type类有一个可以使用的名为GetInterface的方法。

    bool Implements_IFoo(Type t)
    {
        return t.GetInterface(typeof(IFoo).Name) != null;
    }

0
2018-04-27 13:47



它检查整个层次结构中的所有接口,因此第二个用例失败 Implements_IFoo(typeof(Bar)); - mellamokb