确定一个类是否实现了一个非常特定的接口

11

关于这个主题有很多问题,但我有一个稍微改变了的版本。

我们有以下的代码:

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

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

现在,故事的转折点:方法 Implements_IFoo 只有在类型仅实现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()中是否存在这些接口。但我想知道是否有更加优美的解决方案。

顺便说一句,这个问题源于我找到的一些代码,该代码在类上使用此检查(if(obj.GetType() == typeof(BaseClass)) { ... })。 现在,我们将类替换为接口。还要说明的是,我正在将此检查实现为布尔标志,因此这个问题纯粹是假设性的。


1
我真的很好奇你为什么需要这种自省。很有可能是你的设计出了问题。 - tdammers
下次评论之前请仔细阅读问题,我已经解释过这是一个假设性问题;) - Jefim
6个回答

9

因为听起来很有趣,所以我尝试了一下,这个方法在你的例子中可行:

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在类型的精确级别之外的任何级别上。
它还检测接口是否通过基础类型继承。不确定这是否符合您的要求。
尽管如其他人所说,如果这确实是您的要求,那么您的设计可能存在问题。(编辑:刚注意到您的问题纯属假设。那当然没问题 :))

谢谢,那正是我想表达的。因为你的回答是第一个正确的,所以我将其标记为正确答案。 :) - Jefim

3
请参考以下网站,了解如何实现此功能:C# is关键字用法。你可以使用“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;
}

我知道is关键字,但它并不能解决问题。请查看我的问题中带有示例的部分。请注意,IBar是从IFoo派生而来的。因此,Bar也通过IBar实现了它。is将为expr返回true。Bar is IFoo,但这不是期望的结果。 - Jefim

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

1

这应该能解决问题:

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

可能有更有效率的方法。


我猜你是想用typeof(IFoo).IsAssignableFrom(t)而不是t is IFoo,但没错,这就是它的作用 :) - Jefim
而且,以防万一 - 该代码不检查基类(我的问题中没有明确定义),并且当类型没有任何接口时的条件(=>“ .Any(..)”返回false)。 - Jefim

0

你有尝试使用关键字is吗?

顺便提一句,在一般情况下,如果您有一个逻辑案例,其中某个类需要是某个基类的类型,但不是继承者之一,那么这可能是错误的OO设计,可能会违反Liskov替换原则


再次强调,使用is并不能解决问题,因为它会将expr.Bar is IFoo返回为true(而期望的输出是false,因为Bar是通过IBar实现了IFoo接口)。如果您仔细阅读了问题,就不需要提到Liskov和OO设计。关键词:假设/理论。;) - Jefim

0
Type类有一个名为GetInterface的方法,您可以使用它。
    bool Implements_IFoo(Type t)
    {
        return t.GetInterface(typeof(IFoo).Name) != null;
    }

它检查整个层次结构中的所有接口,因此无法通过第二个用例“Implements_IFoo(typeof(Bar));”。 - mellamokb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接