Czy w C # mogę rzutować zmienną typu object na zmienną typu T, gdzie T jest zdefiniowane w zmiennej Type?
c#
reflection
types
theringostarrs
źródło
źródło
Type
zmienną, możesz użyć refleksji, aby utworzyć instancję tego typu. A następnie możesz użyć ogólnej metody, aby zwrócić pożądany typ, wywnioskując go z parametru tego typu. Niestety, każda metoda refleksji, która tworzy instancję typu, będzie miała typ zwracanyobject
, więc Twoja ogólnaCastByExample
metoda również będzie używaćobject
. Więc tak naprawdę nie ma na to sposobu, a nawet gdyby tak było, co byś zrobił z nowo rzuconym obiektem? Nie możesz użyć jego metod ani niczego, ponieważ nie znasz jego typu.object
lubdynamic
. Jeśli chcesz dynamicznie ładować moduły zewnętrzne, możesz mieć klasy współużytkowane wspólny interfejs i rzutować na niego obiekt. Jeśli nie kontrolujesz kodu strony trzeciej, utwórz małe opakowania i zaimplementuj na nim interfejs.Odpowiedzi:
Oto przykład obsady i konwersji:
Edytować:
Niektóre osoby w komentarzach twierdzą, że ta odpowiedź nie odpowiada na pytanie. Ale linia
(T) Convert.ChangeType(input, typeof(T))
stanowi rozwiązanie.Convert.ChangeType
Metoda usiłuje przekształcić dowolny obiekt do rodzaju świadczonych jako drugi argument.Na przykład:
Pisałem odpowiedź z rodzajowych, ponieważ myślę, że jest to bardzo prawdopodobne, Znak zapachy kodu kiedy chcesz obsadą
a something
abya something else
bez obsługi rzeczywisty typ. Z odpowiednimi interfejsami, które nie powinny być potrzebne 99,9% razy. Być może istnieje kilka skrajnych przypadków, jeśli chodzi o refleksję, że może to mieć sens, ale zalecałbym unikanie tych przypadków.Edycja 2:
Kilka dodatkowych wskazówek:
object
lubdynamic
.źródło
T
taką.Convert.ChangeType(input, typeof(T));
daje rozwiązanie. Możesz łatwo zastąpićtypeof(T)
istniejącą zmienną typu. Lepszym rozwiązaniem (jeśli to możliwe) byłoby całkowite zapobieganie typowi dynamicznemu.T
której nie jest dostępna.T
ale nadal otrzymujesz tylkoobject
jako odniesienie. hmm, uznałem pytanie za interesujące w założeniu, że OP ma tylkoType
zmienną i żadnych innych informacji. Jakby sygnaturą metody jestConvert(object source, Type destination)
:) Niemniej jednak dostaję punktInne odpowiedzi nie wspominają o typie „dynamicznym”. Aby dodać jeszcze jedną odpowiedź, możesz użyć typu „dynamicznego” do przechowywania wynikowego obiektu bez konieczności rzutowania skonwertowanego obiektu na typ statyczny.
Należy pamiętać, że przy użyciu opcji „dynamicznej” kompilator omija sprawdzanie typu statycznego, co może powodować ewentualne błędy w czasie wykonywania, jeśli użytkownik nie jest ostrożny.
źródło
Oto moja metoda rzutowania obiektu, ale nie na zmienną typu ogólnego, a na
System.Type
dynamicznie:Tworzę wyrażenie lambda w czasie wykonywania przy użyciu
System.Linq.Expressions
typuFunc<object, object>
, który rozpakowuje dane wejściowe, wykonuje pożądaną konwersję typu, a następnie podaje wynik w ramce. Nowy jest potrzebny nie tylko dla wszystkich typów, na które rzutuje się, ale także dla typów, które są rzutowane (z powodu etapu rozpakowywania). Tworzenie tych wyrażeń jest bardzo czasochłonne, ze względu na odbicie, kompilację i dynamiczne budowanie metod wykonywane pod maską. Na szczęście po utworzeniu wyrażenia można wywoływać wielokrotnie i bez nadmiernego obciążenia, więc każdą z nich przechowuję w pamięci podręcznej.Pamiętaj, że to nie jest magia. Przesyłanie nie występuje w kodzie, podobnie jak w przypadku
dynamic
słowa kluczowego, konwertowane są tylko podstawowe dane obiektu. W czasie kompilacji wciąż musimy starannie zastanawiać się, jakiego typu może być nasz obiekt, co czyni to rozwiązanie niepraktycznym. Napisałem to jako włamanie do wywoływania operatorów konwersji zdefiniowanych przez dowolne typy, ale być może ktoś może znaleźć lepszy przypadek użycia.źródło
using System.Linq.Expressions;
Type t = typeof(MyGeneric<>).MakeGenericType(obj.OutputType); var a = (t)Convert.ChangeType(obj, t); var b = (t)Caster.Cast(t, obj);
Type
. Nie możesz rzutować przy użyciu normalnej składni rzutowania, jeśli wszystko, co masz, to obiekt Type. Jeśli chcesz mieć możliwość używania obiektu jako jakiegoś typu T w czasie kompilacji, a nie środowiska wykonawczego, musisz rzutować go przy użyciu zmiennej typu lub po prostu rzeczywistej nazwy typu. Możesz zrobić to pierwsze, używając odpowiedzi Zaphraxa.Odkładając boksowanie i rozpakowywanie na bok dla uproszczenia, nie ma konkretnej akcji środowiska wykonawczego związanej z rzutowaniem wzdłuż hierarchii dziedziczenia. Jest to głównie czas kompilacji. Zasadniczo rzutowanie mówi kompilatorowi, aby traktował wartość zmiennej jako inny typ.
Co możesz zrobić po obsadzie? Nie znasz typu, więc nie będziesz mógł wywoływać żadnych metod. Nie byłoby nic specjalnego do zrobienia. W szczególności może być przydatny tylko wtedy, gdy znasz możliwe typy w czasie kompilacji, rzutuj go ręcznie i obsługuj każdą sprawę osobno za pomocą
if
instrukcji:źródło
Jak mogłeś to zrobić? Potrzebujesz zmiennej lub pola typu T, w którym możesz przechowywać obiekt po rzutowaniu, ale jak możesz mieć taką zmienną lub pole, jeśli znasz T tylko w czasie wykonywania? Więc nie, nie jest to możliwe.
źródło
CastTo
metodęObject
?Jeśli chodzi o casting do typu Enum:
I nazwiesz to tak:
Było to dla mnie niezbędne w przypadku uzyskania wartości atrybutu Opis kilku typów wyliczenia według wartości int:
i wtedy:
Alternatywnie (lepsze podejście) taki rzut mógłby wyglądać następująco:
źródło
Po tym, jak nie znalazłem nic do obejścia, „Obiekt musi zaimplementować IConvertible” podczas korzystania z odpowiedzi Zyphrax (z wyjątkiem implementacji interfejsu). Próbowałem czegoś niekonwencjonalnego i pracowałem w mojej sytuacji.
Korzystanie z pakietu nuget Newtonsoft.Json ...
źródło
Szkoda, problem polega na tym, że nie masz T.
masz tylko zmienną Type.
Wskazówka dla stwardnienia rozsianego, jeśli możesz zrobić coś takiego
TryCast<typeof(MyClass)>
gdyby rozwiązał wszystkie nasze problemy.
źródło
Nigdy nie zrozumiem, dlaczego potrzebujesz 50 reputacji, aby dodać komentarz, ale musiałem powiedzieć, że odpowiedź @Curt jest dokładnie tym, czego szukałem i mam nadzieję, że ktoś inny.
W moim przykładzie mam ActionFilterAttribute, którego użyłem do aktualizacji wartości dokumentu poprawki json. Nie wiedziałem, jaki jest model T dla dokumentu poprawki, musiałem serializować i deserializować go do zwykłego JsonPatchDocument, modyfikować go, a następnie, ponieważ miałem typ, serializować i deserializować go z powrotem do typu.
źródło
źródło
jeszcze czystszy:
źródło
Jeśli chcesz rzutować obiekty w czasie wykonywania bez znajomości typu miejsca docelowego, możesz użyć odbicia, aby utworzyć dynamiczny konwerter.
To jest wersja uproszczona (bez metody generowania buforowania):
możesz to nazwać:
źródło