2012-04-27 11 views
11

このトピックに関する質問はたくさんありますが、少し変更されたバージョンがあります。クラスが特定のインターフェイスを実装しているかどうかを確認する

私たちは、次のコードを持っている:今

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

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

、物語のツイスト:タイプだけではなくIFoo由来のいずれかのインターフェイスIFooを実装する場合にのみtrueを返すImplements_IFoo方法を。そこIFoo由来の多数のインタフェースすることができ、あなたが必ずしも彼らの存在について知らないことを

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

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

注:ここで説明するために、この方法のいくつかの例があります。

明白な方法は、反射を通してIFooから派生したすべてのインターフェイスを見つけて、typeof(Bar).GetInterfaces()がその中に存在するものだけをチェックすることです。しかし、私は誰かがより洗練されたソリューションを考え出すことができるかどうか疑問に思っていました。

PS質問は私がクラス(if(obj.GetType() == typeof(BaseClass)) { ... })でこのチェックを使用することがわかったいくつかのコードから発生します。私たちはインターフェイスを持つクラスをその特定のコードに置き換えています。また、ちょうどその場合 - 私はブール値のフラグとしてこのチェックを実装しているので、この質問はまったく仮説的なものです。

+1

最初にこの種のイントロスペクションが必要なのは本当に不思議です。デザインが間違っている可能性があります。 – tdammers

+0

次回のコメントをする前に、最後まで質問を読んでください - これは仮説的な質問であると私はすでに説明しました;) – Jefim

答えて

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が存在するかどうかを確認します。

また、インタフェースがベースタイプで継承されているかどうかを検出します。それがあなたが望むものなのかどうかは分かりません。

まだ、他の人がすでに言っているように、これが本当に必要条件であれば、デザインに問題があるかもしれません。

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

はおそらく、より効率的な方法があります。これは、トリックを行う必要があります

+0

ありがとう、それはまさに私が意味していたものです。最初の正しい答えであるため、答えを正しいとマークしてください。 :) – Jefim

0

キーワードisを試しましたか?

一般的に、いくつかのクラスが基本クラスの型である必要があり、継承者の1つではない論理的なケースがある場合は、間違ったOOデザインです(Liskov substitution principleに違反する可能性があります)。

+1

'Type'オブジェクトについて? – mellamokb

+0

再び 'is'はexprに' true'を返すので助けにはなりません。 'Bar is IFoo'(BarはIFoo〜IBarを実装するので、希望する出力は' false'です)。あなたが質問を徹底的に読んでいれば、LiskovとOOの設計について言わなくてもいいでしょう。キーワード:仮説/理論。 ;) – Jefim

3

これをどのように実装できるかについては、次のサイトを参照してください。

C# is keyword usage

基本的には、オブジェクトがそれのクラス継承スタックの一部として、クラスタイプに生息するかどうかを判断するために「です」キーワードを使用することができます。あなたの例機能付きラインで

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; 
} 
+0

私は 'is'キーワードを知っており、問題は解決しません。私の質問の部分を例で見てください。 IBarはIFooから派生していることに注意してください。したがって、BarはIBarによっても実装します。 'is'はexprに対してtrueを返します。バーはIFooですが、それは望ましい結果ではありません。 – Jefim

0

Typeクラスを使用すると、使用することができますGETINTERFACEと呼ばれる方法があります。

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

階層全体のすべてのインタフェースをチェックするので、2番目のユースケース 'Implements_IFoo(typeof(Bar));には失敗します。 – mellamokb

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; 
} 
+0

答えをありがとう!これはまさに私が意味していたものです。 – Jefim

1

:(EDITは。ちょうどあなたの質問は、それは:)もちろんの罰金純粋に架空のですされて気づきました)。

+0

'tはIFoo'の代わりに' typeof(IFoo).IsAssignableFrom(t) 'を意味していたと思いますが、これは物事です:) – Jefim

+0

ちょうどその場合 - そのコードは基底クラスをチェックしません私の質問では明確に定義されていませんでした)、型にインターフェースがない場合(=> '.Any(..)'はfalseを返します)。 – Jefim

関連する問題