2010-01-13 10 views
5

Podczas wywoływania typeof (Bar) .GetInterfaces() w następującym scenariuszu metoda zwraca IFoo i IBar.Znajdź natychmiast zaimplementowane interfejsy na typie

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

Czy istnieje sposób, że mogę znaleźć tylko natychmiastowe interfejs (IBAR) na pasku?

+1

Dlaczego chciałbyś to zrobić? Brzmi dla mnie jak błąd projektowy w twoim kodzie;) –

+0

Zwrócona tablica nie jest deterministyczna. – sduplooy

+0

@Oliver, system mapuje interfejsy do konkretnych typów. Problem polega na tym, że inny typ może implementować IFoo, ale nie chcemy kojarzyć interfejsu IFoo z klasą Bar, ale raczej z interfejsem IBar. – sduplooy

Odpowiedz

12

Nie, nie ma czegoś takiego jak "bezpośredni" interfejs w skompilowanym kodzie. Twoja klasa jest skutecznie kompilowana jako:

class Bar : IBar, IFoo { } 

i nie można rozróżnić tych dwóch. Jedyne, co możesz zrobić, to sprawdzić je wszystkie i sprawdzić, czy dwa lub więcej interfejsów dziedziczy po sobie nawzajem (i nawet w takim przypadku nie można naprawdę sprawdzić, czy autor klasy wyraźnie wspomniał o interfejs bazy w kodzie lub nie):

static IEnumerable<Type> GetImmediateInterfaces(Type type) 
{ 
    var interfaces = type.GetInterfaces(); 
    var result = new HashSet<Type>(interfaces); 
    foreach (Type i in interfaces) 
     result.ExceptWith(i.GetInterfaces()); 
    return result; 
} 
1
public interface IRoo { } 
public interface ISoo : IRoo { } 
public interface IMoo : ISoo { } 
public interface IGoo : IMoo { } 
public interface IFoo : IGoo { } 
public interface IBar : IFoo { } 
public class Bar : IBar { } 

private void button1_Click(object sender, EventArgs e) { 
    Type[] interfaces = typeof(Bar).GetInterfaces();  
    Type immediateInterface = GetPrimaryInterface(interfaces); 
    // IBar 
} 

public Type GetPrimaryInterface(Type[] interfaces) 
{ 
    if (interfaces.Length == 0) return null; 
    if (interfaces.Length == 1) return interfaces[0]; 

    Dictionary<Type, int> typeScores = new Dictionary<Type, int>(); 
    foreach (Type t in interfaces) 
     typeScores.Add(t, 0); 

    foreach (Type t in interfaces) 
     foreach (Type t1 in interfaces) 
      if (t.IsAssignableFrom(t1)) 
       typeScores[t1]++; 

    Type winner = null; 
    int bestScore = -1; 
    foreach (KeyValuePair<Type, int> pair in typeScores) { 
     if (pair.Value > bestScore) { 
      bestScore = pair.Value; 
      winner = pair.Key; 
     } 
    } 
    return winner; 
} 
+0

Interesujący wyglądający kod, ale dlaczego 'GetPrimaryInterface' zwraca tylko jeden typ interfejsu? Wygląda na to, że musiałby on potencjalnie zwrócić wiele typów interfejsów, aby były przydatne. – HappyNomad

0

ten wybiera interfejs z najdłuższym drzewa dziedziczenia.

typeof(Bar) 
    .GetInterfaces() 
    .OrderByDescending(i => i.GetInterfaces().Length) 
    .FirstOrDefault() 

To wystarczyło dla mojego przypadku użycia.