2010-03-30 4 views
5

Geben Sie eine Basisklasse Base, ich möchte diese ein Verfahren Prüfung schreiben, wie:Wie findet man heraus, ob ein Objekttyp IEnumerable <X> implementiert, wobei X aus Basis Reflection mit leitet

private static bool Test(IEnumerable enumerable) 
{ 
... 
} 

, so dass Test ist wahr wenn die Art der o implementiert jede Schnittstelle von IEnumerable<X> wo X von Base leitet, so dass, wenn ich dies tun würde:

public static IEnumerable<string> Convert(IEnumerable enumerable) 
{ 
    if (Test(enumerable)) 
    { 
     return enumerable.Cast<Base>().Select(b => b.SomePropertyThatIsString); 
    } 

    return enumerable.Cast<object>().Select(o => o.ToString()); 
} 

..., dass es das richtige zu tun, mit Reflecti auf. Ich bin mir sicher, dass es eine Frage des Gehens über alle Schnittstellen des Typs ist, um den ersten zu finden, der den Anforderungen entspricht, aber ich habe eine harte Zeit, den generischen IEnumerable<> unter ihnen zu finden.

Natürlich, ich könnte dies berücksichtigen:

public static IEnumerable<string> Convert(IEnumerable enumerable) 
{ 
    return enumerable.Cast<object>().Select(o => o is Base ? ((Base)o).SomePropertyThatIsString : o.ToString()); 
} 

... aber denken Sie an es als ein Gedankenexperiment.

+0

Ihre Code-Schnipsel machen keinen Sinn, woher kommt "o"? –

+12

Vielleicht sollten Sie sich über Lambda-Ausdrücke informieren. –

Antwort

16

Sie auch eine LINQ Abfrage verwenden könnte, die wie folgt aussehen könnte.

public static bool ImplementsBaseType(IEnumerable objects) 
{ 
    int found = (from i in objects.GetType().GetInterfaces() 
       where i.IsGenericType && 
         i.GetGenericTypeDefinition() == typeof(IEnumerable<>) && 
         typeof(MyBaseClass).IsAssignableFrom(i.GetGenericArguments()[0]) 
       select i).Count(); 

    return (found > 0); 
} 

Dieser Code setzt die folgenden using-Anweisungen:

using System; 
using System.Collections; 
using System.Collections.Generic; 
using System.Linq; 

Da dies nur ein Gedankenexperiment. Hier ist eine andere Implementierung als eine Erweiterungsmethode.

public static class ConversionAssistants 
{ 
    public static bool GenericImplementsType(this IEnumerable objects, Type baseType) 
    { 
     foreach (Type type in objects.GetType().GetInterfaces()) 
     { 
      if (type.IsGenericType) 
      { 
       if (type.GetGenericTypeDefinition() == typeof(IEnumerable<>)) 
       { 
        if (baseType.IsAssignableFrom(type.GetGenericArguments()[0])) 
         return true; 
       } 
      } 
     } 
     return false; 
    } 
} 
+2

statt arg.BaseType == typeof (MyBaseClass), könnte man sagen typeof (MyBaseClass) .IsAssignableFrom (arg), oder? –

+0

@Dave: Ja, das funktioniert auch. – VoidDweller

+1

IsAssignableFrom' ist besser, weil '==' nur funktioniert, wenn der Typ * direkt * von MyBaseClass erbt –

0

können Sie die Type.FindInterfaces verwenden alle IEnumerable<> Schnittstellen, um die Art implementiert, um herauszufiltern und die generischen Parameter überprüfen (durch Type.GetGenericArguments) auf jedem von ihnen zu sehen, ob es Base ist oder erbt von Base.

aktualisieren: Hier ist ein Beispielcode:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Reflection; 

namespace ConsoleApplication1 
{ 
    class Base 
    { 
     string Prop { get; set;} 
    } 

    class A : Base 
    { 
    } 

    class Test : List<A> 
    { 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      try 
      { 
       Test test = new Test(); 
       Type myType = test.GetType(); 

       //string filterCriteria = "IEnumerable`1"; 
       Type typeA = Type.GetType("ConsoleApplication1.A"); 
       string filterCriteria = "System.Collections.Generic.IEnumerable`1[[" + 
             typeA.AssemblyQualifiedName + 
             "]]"; 

       // Specify the TypeFilter delegate that compares the 
       // interfaces against filter criteria. 
       TypeFilter myFilter = new TypeFilter(MyInterfaceFilter); 
       Type[] myInterfaces = myType.FindInterfaces(myFilter, 
        filterCriteria); 
       if (myInterfaces.Length > 0) 
       { 
        Console.WriteLine("\n{0} implements the interface {1}.", 
         myType, filterCriteria); 
        for (int j = 0; j < myInterfaces.Length; j++) 
         Console.WriteLine("Interfaces supported: {0}.", 
          myInterfaces[j].ToString()); 
       } 
       else 
        Console.WriteLine(
         "\n{0} does not implement the interface {1}.", 
         myType, filterCriteria); 
      } 
      catch (ArgumentNullException e) 
      { 
       Console.WriteLine("ArgumentNullException: " + e.Message); 
      } 
      catch (TargetInvocationException e) 
      { 
       Console.WriteLine("TargetInvocationException: " + e.Message); 
      } 
      catch (Exception e) 
      { 
       Console.WriteLine("Exception: " + e.Message); 
      } 
     } 

     public static bool MyInterfaceFilter(Type typeObj, Object criteriaObj) 
     { 
      // This will be true, if criteria is 
      // System.Collections.Generic.IEnumerable`1[[ConsoleApplication1.A, ConsoleApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] 
      if (typeObj.FullName == criteriaObj.ToString()) 
       return true; 
      // This will be true, if criteria is 
      // IEnumerable`1 
      // You will still need to check the generic parameters on the original type 
       // (generic parameters are not exposed on Type instances for interfaces 
      else if (typeObj.Name == criteriaObj.ToString()) 
       return true; 
      else 
       return false; 
     } 
    } 
} 
+0

Das ist, was ich dachte, aber wie überprüfe ich, ob eine Schnittstelle eine Instanz der generischen Schnittstelle IEnumerable <> ist? –

-2

Ich habe vor kurzem einen Code geschrieben, der über jede Sammlung iterieren muss.

Als Legacy-.NET-App hatte ich nicht einmal Generika für mich verfügbar!

Hier ein Auszug:

var t = objects.GetType(); // to be compatible with the question 

bool isIEnumerable = false; 
foreach (var i in t.GetInterfaces()) 
{ 
    if (i == typeof(IEnumerable)) 
    { 
     isIEnumerable = true; 
     break; 
    } 
} 

Ich fand, dass auch die .NET 1.1 Collection-Klassen wie SqlParameterCollection IEnumerable waren.
Es fängt auch generische Sammlungen wie die Liste <> wie auch IEnumerable.

Ich hoffe, das hilft jemandem.

+0

Die Frage bezieht sich auf Generics. Außerdem können Sie einfach "Objekte IEnumerable" oder "Objekte als IEnumerable" verwenden, um zu testen, ob es aufzählbar ist. Ihre Lösung ist ziemlich kompliziert. –

Verwandte Themen