2009-08-18 15 views
5

Zobacz mam takiej sytuacji ...Pass Typ dynamicznie <T>

object myRoledata = List<Roles>() --> (some list or Ienumerable type) 

Teraz mam metoda rodzajowa, która tworzy obiekt XML z List<T> - coś takiego ..

public string GetXML<T>(object listdata) 
{ 
    List<T> objLists = (List<T>)Convert.ChangeType(listData, typeof(List<T>)); 
    foreach(var obj in listdata) 
    { 
     //logic to create xml 
    } 
} 

teraz w celu uruchomienia tej metody muszę zrobić tak:

string xml = GetXML<Roles>(myRoledata); 

Teraz nie wiem, co Type może przyjść do mnie, aby przejść do metody GetXML. Mam metodę, która będzie wywoływać GetXML dla różnychs np. Roles, Users itp

teraz mogę dostać Type w List<> jak ten

Type genericType = obj.GetType().GetGenericArguments()[0]; 

ale nie może przekazać go jak ten

string xml = GetXML<genericType>(myRoledata); 

Czy mimo to, w którym mogę przekazać wszelkie genericTypes do GetXML metoda?

+0

Prawdopodobnie chcesz wyjaśnić w pytaniu, czy (prawdopodobnie wiele) rodzajów T są nieznane podczas kompilacji, czy nie. Jeśli są one znane, odpowiedź Ulrika ma sens, tzn. Przestaje rzutować i wymusza typ argumentu (być może z kilkoma przeciążeniami). Jeśli nie jest znana, musisz użyć refleksji, w jakiejś formie, a odpowiedź Marks pokazuje najprostszy i najprawdopodobniej najlepszy sposób, aby to osiągnąć. – ShuggyCoUk

Odpowiedz

2

To jest problem, który prawdopodobnie chcesz uniknąć rozwiązywania. To jest możliwe, dzięki odbiciu, do wywoływania metod dynamicznie, bez statycznego ich rozdzielania - ale to rodzaj pokonania całego punktu adnotacji typu.

Albo to zrobić:

public string GetXML(IEnumerable listdata) { 
    foreach(object obj in listdata) 
     //logic to create xml 
} 

... które teraz mogą dzwonić z dowolnego IEnumerable lub napisać to "nowoczesny" sposób jak:

public string GetXML(IEnumerable<object> listdata) { 
    foreach(object obj in listdata) 
     //logic to create xml 
} 

... co można zadzwonić z dowolnym IEnumerable przez GetXML(someEnumerable.Cast<object>()) i w C# 4.0 nawet bezpośrednio przez kowariancję.

Jeśli potrzebujesz typ elementu wykonywania, można dostać go za pomocą .GetType() na każdym elemencie, albo po prostu przekazać go jako parametr (i zapewniają nadpisanie dla wstecznej kompatybilności):

public string GetXML(Type elementType, IEnumerable<object> listdata) { 
    foreach(object obj in listdata) 
     //logic to create xml 
} 

public string GetXML<T>(IEnumerable<T> listdata) { 
    return GetXML(typeof(T),listdata.Cast<object>()); 
} 

Nawiasem mówiąc, jeśli konstruujesz XML, ciąg jest prawdopodobnie mniej niezawodnym wyborem typu zwrotu: jeśli to możliwe, możesz zamiast tego pracować z czymś takim, jak XElement - i uzyskać gwarancję ważności xml do uruchomienia.

+0

Właściwie odradzam używanie 'IEnumerable ' bezpośrednio, co najmniej do C# 4.0; prawdopodobnie nie zrobi tego, czego chcesz, z powodu braku rozbieżności w parametrach typu. 'IEnumerable' jest więcej niż użyteczny. –

+0

Cóż, szczególnie dla IEnumerable, kowariancja jest mniejszym problemem z powodu operatora Linq '.Cast <>'. Jeśli chcesz wywołać metodę z parametrem 'IEnumerable ' i masz 'IEnumerable myEnum' z jakimś obiektem' T! = ', Możesz po prostu zrobić 'myEnum.Cast ()' z niewielką utratą czytelności i prędkość. Wadą stylistyki nietypowego 'IEnumerable' jest brak jawnego wsparcia' IDisposable', fakt, że 'System.Collections' nie znajduje się w domyślnym zestawie zastosowań, które VS.NET dodaje do nowych plików, i że jest to mniej popularny idiom. –

+0

W każdym razie, dzięki za komentarz - nietypowy "IEnumerable" również jest dobrym wyborem. –

7

Aby to zrobić, musisz użyć odbicia;

typeof(SomeClass).GetMethod("GetXML").MakeGenericMethod(genericType) 
     .Invoke(inst, new object[] {myRoleData}); 

gdzie inst jest null jeśli jest to metoda statyczna, this dla bieżącej instancji (w tym przypadku można także użyć GetType() zamiast typeof(SomeClass)) lub obiekt docelowy inaczej.

+2

Ale czy to nie jest całkowicie błędne? Przez wywołanie metody w ten sposób, naprawdę nie ma powodu, aby w ogóle używać generycznych, ponieważ wyrzucasz kontrolę typów i dostajesz wszystkie błędy w czasie wykonywania. –

+1

Moją intepretacją pytania jest to, że chcieli oddzielić je od leków generycznych. Jeśli ta interpretacja jest nieprawidłowa, twoje podejście jest zdecydowanie bardziej odpowiednie. To zależy od scenariusza ;-p –

7

Ponieważ oddać swój parametr listData jako Lista < T> w pierwszej linii od wybranej metody, dlaczego nie można po prostu zmienić podpis metody do

public string GetXML<T>(List<T> listdata) 

w ten sposób, nie trzeba używać refleksji, aby uzyskać ogólne argumenty.

EDYCJA: Widzę, że musisz być w stanie zaakceptować kolekcje IEnumerable, a nie tylko listy. Zastanów się więc nad zmianą sygnatury metody na

public string GetXML<T>(IEnumerable<T> listdata) 
0

Masz dobry pomysł, ale używasz niewłaściwej metody. Spójrz na Type.MakeGenericType lub MethodInfo.MakeGenericMethod. To zajmie kilka linii więcej niż twój przykład, ale powinno być proste do rozwiązania.

GetGenericArguments() może zostać użyty do uzyskania typu Role z listy. Jest to inna droga.

Przy okazji: Wygląda na to, że implementujesz jakąś serializację XML. Upewnij się, że sprawdziłeś istniejące klasy, zanim wymyślisz nowe koło.;-)

2

nie wiem swoją sytuację, ale jest to możliwe, aby przerobić swoją funkcję jako:

public string GetXML<T>(IEnumerable<T> listdata) 
{ 
    foreach(var obj in listdata) 
    { 
     //logic to create xml 
    } 
} 

Następnie można nazwać jako:

List<Role> myList; 
GetXML(myList); 

Możesz dodać typ parametry tak daleko, jak to konieczne, aby je wspierać, aż dotrzesz do miejsca, które wie, co to jest typ bryłowy.

Powiązane problemy