2010-02-17 11 views
5

muszę używać rodzajowy interfejs jak poniżej:Funkcja powrocie typu rodzajowego, którego wartość jest znana tylko w czasie wykonywania

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

Celem realizacji tego interfejsu jest zwracany przez ogólny sposób jak poniżej:

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

Typ T jest nieznany do czasu wykonywania.

Korzystając z odbicia, jestem w stanie wywołać metodę GetContainer<T> i uzyskać wynik.

Mój problem polega na tym, że nie wiem, jak wyliczyć wynik, który ma typ Object (dlatego nie mogę go przesłać do IEnumerable).

Próbowałem również odlewy następująco ale to nie działa (mówi „Oczekuje Type”):

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

gdzie type jest typem Runtime myService jest usługa narażając metodę GetContainer<T> i property jest w razie potrzeby typu IProperty.

UPDATE: patrz mój kompletne rozwiązanie w moim blogu: http://stefanoricciardi.com/2010/02/18/generics-with-type-uknown-at-compile-time/

+0

możliwe duplikat (http://stackoverflow.com/questions/232535/how- to-use-reflection-to-call-generic-method) – nawfal

Odpowiedz

1

typeof (IContainer <>). MakeGenericType (typ) będzie podlegał jedynie ocenie w czasie wykonywania, podczas gdy "as" musi znać typ w czasie kompilacji.

To, czego naprawdę nie rozumiem, to ten komentarz: Moim problemem jest to, że nie wiem, jak wyliczyć wynik, który ma typ Object (dlatego nie mogę go rzucić do IEnumerable).

myContainer może być Obiektem, ale z pewnością można go przesłać do IEnumerable? Jeśli nie może, to nie można go wymienić.

1

Twój typ T musi być znany przez kompilator, więc to nie będzie działać. Możesz spróbować stworzyć ogólną wersję interfejsu, taką jak ta:

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

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

W ten sposób masz coś do obsłużenia i możesz z niego korzystać.

0

Jeśli myślisz o przeniesieniu do .Net 4, to zapewnia to typ dynamic.

0

Zakładam, że Twój obiekt zostanie zwrócony jako jedna z ograniczonej liczby typów, więc dlaczego nie przetestować przed tymi, które są przed rzutowaniem, np. czy obiekt jest tą klasą?

+0

Niestety nie mogę przyjąć takiego założenia, ponieważ mój kod jest częścią biblioteki, która może być ponownie wykorzystana. Podczas gdy wiem, że najczęściej będą traktowane głównie ciągi znaków, podwójne i dziesiętne, nie mogę wykluczyć innych typów "a priori". Jeśli wszystko inne zawiedzie, być może będę musiał iść tą trasą i zgłaszać wyjątki dla nieoczekiwanych typów. –

+0

@Stefano - przetestuj typ obiektu na IEnumerable w ten sposób, że możesz go tylko przesłać np. do użycia w instrukcji foreach, jeśli twoja klasa obiektów dziedziczy IEnumerable. – ChrisBD

0

Przepraszam, jeśli źle zrozumiałem, miałem problem ze zrozumieniem, jaki był twój cel. Czy szukasz czegoś takiego?

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

Nie, już pominąłem ten punkt. Zapełniłem już mój kontener i działa. Mój problem pojawia się później, czyli pobierania pojedynczej zawartości z pojemnika. –

1

Po pierwsze, podczas rzucania potrzebujesz typu (double, int); typeof przyjmuje argument typu i zwraca klasę typu Type.

 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 

Po drugie, jest tu jakiś przykład kodu: [? Jak używać odbicie zadzwonić metoda rodzajowa]

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); 
     } 
    } 
} 
Powiązane problemy