2010-02-17 7 views
5

Ich brauche eine generische Schnittstelle wie die verwenden folgende:Funktion, die einen generischen Typ, deren Wert bekannt ist, nur zur Laufzeit

public interface IContainer<T> 
{ 
    IEnumerable<IContent<T>> Contents { get; } 
} 

Eine Aufgabe der Umsetzung dieser Schnittstelle durch eine generische Methode, wie die folgende zurückgegeben:

IContainer<T> GetContainer<T>(IProperty property); 

Typ T ist bis zur Laufzeit unbekannt.

Mit Reflection kann ich die GetContainer<T> Methode aufrufen und das Ergebnis erhalten.

Mein Problem ist, dass ich nicht weiß, wie man das Ergebnis, das Object Typ hat (daher kann ich es nicht umwandeln IEnumerable).

Ich habe auch versucht, wie folgt Gießen, aber es funktioniert nicht (es heißt „Typ erwartet wird“):

var myContainer = genericMethodInfo.Invoke(
          myService, 
          new object[] { property }) 
    as typeof(IContainer<>).MakeGenericType(type); 

wo type der Laufzeittyp ist, myService ist der Dienst Aussetzen der GetContainer<T> Verfahren und property ist vom Typ IProperty nach Bedarf.

UPDATE: meine komplette Lösung in meinem Blog sehen: http://stefanoricciardi.com/2010/02/18/generics-with-type-uknown-at-compile-time/

+0

möglich Duplikat (http://stackoverflow.com/questions/232535/how- to-use-reference-to-call-generic-Methode) – nawfal

Antwort

1

typeof (IContainer <>) .MakeGenericType (type) wird nur zur Laufzeit ausgewertet, während "as" den Typ zum Compilerzeitpunkt kennen muss.

Was ich wirklich nicht verstehe, ist dieser Kommentar: Mein Problem ist, dass ich nicht weiß, wie man das Ergebnis vom Typ Object aufzählt (daher kann ich es nicht in IEnumerable umwandeln).

myContainer kann ein Objekt sein, aber es kann sicher in IEnumerable umgewandelt werden? Wenn es nicht möglich ist, kann es nicht aufgezählt werden.

1

Ihre Art T vom Compiler bekannt sein müssen, so dass dies nicht funktioniert. Sie können versuchen, eine nicht generische Version von Ihrer Schnittstelle zu machen, wie folgt aus:

public interface IContainer 
{ 
    IEnumerable<IContent> Contents { get; } 
} 

public interface IContainer<T> : IContainer { ... } 

diese Weise können Sie etwas zu werfen haben und sind in der Lage, es zu benutzen.

0

Wenn Sie daran denken, zu .Net 4 zu wechseln, ist das der Typ dynamic.

0

Ich gehe davon aus, dass Ihr Objekt nur als eine von einer begrenzten Anzahl von Typen zurückgegeben wird, also warum nicht gegen diese vor dem Gießen z. Wenn Objekt diese Klasse ist?

+0

Leider kann ich keine solche Annahme machen, weil mein Code Teil einer Bibliothek ist, die wiederverwendet werden könnte. Während ich weiß, dass hauptsächlich Strings, Doppel und Dezimalzahlen behandelt werden, kann ich andere Typen "a priori" nicht ausschließen. Wenn alles andere fehlschlägt, muss ich möglicherweise diese Route gehen und Ausnahmen für unerwartete Typen auslösen. –

+0

@Stefano - Testen Sie Ihren Objekttyp gegen IEnumerable. So können Sie sicherstellen, dass Sie nur z. zur Verwendung in einer foreach-Anweisung, wenn Ihre Objektklasse IEnumerable erbt. – ChrisBD

0

Tut mir leid, wenn ich falsch verstanden habe, hatte ich Probleme zu verstehen, was genau Ihr Ziel war. Suchst du nach so etwas?

var myContainer = typeof(ClassWithGetContainer) 
       .GetMethod("GetContainer") 
       .MakeGenericMethod(runtimeType) 
       .Invoke(InstanceOfClassWithGetContainer, new object[] { property }); 
+0

Nein, ich bin schon über diesen Punkt hinaus. Ich habe bereits myContainer befüllt und es funktioniert. Mein Problem kommt danach, das ist das Abrufen der einzelnen Inhalte aus dem Container. –

1

Zuerst, wenn Sie Casting benötigen Sie einen Typ (double, int); typeof verwendet ein type-Argument und gibt eine Klasse vom Typ Type zurück.

 object x = 0.0; 
    Type t = typeof(double); 
    double y = x as t; //does not compile - t is not a type - it's an instance of type Type 
    double y = x as typeof(double); //same as above 
    double y = x as double; //compiles - double is a type 
    Type z = x as Type; //compiles - Type is a type 

Zweitens, hier einige Beispiel-Code: [? Wie Reflektion verwenden generische Methode aufzurufen]

using System; 
using System.Collections.Generic; 
using System.Collections; 
using System.Reflection; 
using System.Diagnostics; 

namespace TryThis 
{ 
    public interface IContainer<T> 
    { 
     IEnumerable<IContent<T>> Contents { get; } 
    } 
    public interface IContent<T> 
    { 
     T GetMyContent(); 
    } 
    public interface IProperty 
    { } 

    public class Content<T> : IContent<T> 
    { 
     T m_content = default(T); 
     public T GetMyContent() { return m_content; } 
     public Content(T val) { m_content = val; } 
    } 

    public class Contents<T> : IEnumerable<IContent<T>> 
    { 
     List<IContent<T>> m_contents = new List<IContent<T>>(); 
     IEnumerator<IContent<T>> IEnumerable<IContent<T>>.GetEnumerator() { return m_contents.GetEnumerator(); } 
     IEnumerator IEnumerable.GetEnumerator() { return m_contents.GetEnumerator(); } 
     public Contents(params T[] contents) { foreach (T item in contents) m_contents.Add(new Content<T>(item)); } 
    } 

    public class TestGenericContent : IContainer<int> 
    { 
     public IContainer<int> GetContainer(IProperty property) { return this; } 
     public IEnumerable<IContent<int>> Contents { get { return new Contents<int>(1, 2, 3); } } 
    } 

    public static class TryThisOut 
    { 
     static void Test2(object o) 
     { 
     Type t = o.GetType(); 
     Type tInterface = t.GetInterface("IContainer`1"); //could be null if o does not implement IContainer<T> 
     Type tGenericArg = tInterface.GetGenericArguments()[0]; //extracts T from IContainer<T> 
     MethodInfo info = t.GetMethod("GetContainer"); 
     IProperty propArg = null; //null in this example 
     object oContainer = info.Invoke(o, new object[] { propArg }); 

     PropertyInfo prop = tInterface.GetProperty("Contents"); 
     object oContents = prop.GetGetMethod().Invoke(oContainer, null); 
     //oContents is of type IEnumerable<IContent<T>>, which derives from IEnumerable, so we can cast 
     IEnumerable enumeratedContents = oContents as IEnumerable; 

     MethodInfo getContentItem = typeof(IContent<>).MakeGenericType(tGenericArg).GetMethod("GetMyContent"); 
     foreach (object item in enumeratedContents) 
     {    
      object oContentItem = getContentItem.Invoke(item, null); 
      Debug.Print("Item {0} of type {1}", oContentItem, oContentItem.GetType()); 
      //... 
     } 
     } 

     public static void Test() 
     { 
     object o = new TestGenericContent(); 
     Test2(o); 
     } 
    } 
} 
Verwandte Themen