Przydaje się to podczas pracy z COM lub dynamicznie pisanymi językami. Na przykład, jeśli używasz lua lub python do pisania skryptów w swoim języku, bardzo wygodnie jest po prostu wywołać kod skryptowy, tak jakby był to normalny kod.
Dynamiczne słowo kluczowe jest nowością w C # 4.0 i służy do informowania kompilatora, że typ zmiennej może się zmienić lub że nie jest znany do czasu uruchomienia. Pomyśl o tym, że może wchodzić w interakcje z przedmiotem bez rzucania go.
dynamic cust =GetCustomer();
cust.FirstName="foo";// works as expected
cust.Process();// works as expected
cust.MissingMethod();// No method found!
Uwaga: nie musieliśmy przesyłać ani deklarować klienta jako klienta typu. Ponieważ zadeklarowaliśmy, że jest dynamiczny, środowisko wykonawcze przejmuje, a następnie wyszukuje i ustawia dla nas właściwość FirstName. Teraz, oczywiście, kiedy używasz zmiennej dynamicznej, rezygnujesz z sprawdzania typu kompilatora. Oznacza to, że wywołanie cust.MissingMethod () zostanie skompilowane i nie zakończy się niepowodzeniem, dopóki nie zostanie uruchomione. Wynikiem tej operacji jest RuntimeBinderException, ponieważ MissingMethod nie jest zdefiniowany w klasie Customer.
Powyższy przykład pokazuje, jak działa dynamika podczas wywoływania metod i właściwości. Kolejną potężną (i potencjalnie niebezpieczną) funkcją jest możliwość ponownego wykorzystywania zmiennych dla różnych typów danych. Jestem pewien, że programiści Python, Ruby i Perl mogą wymyślić milion sposobów na skorzystanie z tego, ale używam C # tak długo, że wydaje mi się to „złe”.
dynamic foo =123;
foo ="bar";
OK, więc najprawdopodobniej nie będziesz pisać kodu tak jak powyżej. Może się jednak zdarzyć, że ponowne użycie zmiennych może się przydać lub wyczyścić brudny kawałek starszego kodu. Jednym prostym przypadkiem, w którym często się spotykam, jest ciągłe rzucanie między dziesiętną a podwójną.
decimal foo =GetDecimalValue();
foo = foo /2.5;// Does not compile
foo =Math.Sqrt(foo);// Does not compilestring bar = foo.ToString("c");
Druga linia nie jest kompilowana, ponieważ 2.5 jest wpisany jako podwójny, a linia 3 nie jest kompilowana, ponieważ Math.Sqrt oczekuje podwójnej. Oczywiście wszystko, co musisz zrobić, to rzutować i / lub zmienić typ zmiennej, ale mogą zdarzyć się sytuacje, w których użycie dynamiki ma sens.
dynamic foo =GetDecimalValue();// still returns a decimal
foo = foo /2.5;// The runtime takes care of this for us
foo =Math.Sqrt(foo);// Again, the DLR works its magicstring bar = foo.ToString("c");
Osobiście nie podoba mi się myśl użycia dynamicin c # do rozwiązywania problemów, które można rozwiązać (być może nawet lepiej) za pomocą standardowych funkcji c # i pisania statycznego lub co najwyżej za pomocą wnioskowania typu ( var). dynamicpowinien być stosowany tylko w przypadku problemów z interoperacyjnością z DLR. Jeśli piszesz kod w języku statycznym, takim jak c #, zrób to i nie emuluj języka dynamicznego. To po prostu brzydkie.
Philip Daubmeier
40
Jeśli często używasz dynamiczmiennych w swoim kodzie, gdzie ich nie potrzebujesz (jak w przykładzie z kwadratowym korzeniem), rezygnujesz z sprawdzania błędów podczas kompilacji; zamiast tego otrzymujesz możliwe błędy czasu wykonywania.
Philip Daubmeier
33
W większości w porządku, ale kilka drobnych błędów. Po pierwsze, nie jest poprawne stwierdzenie, że dynamiczny oznacza, że typ zmiennej może się zmienić. Ta zmienna jest typu „dynamiczna” (z perspektywy języka C #; z perspektywy CLR zmienna jest typu obiektowego). Typ zmiennej nigdy się nie zmienia. Typem wykonawczym wartości zmiennej może być dowolny typ zgodny z typem zmiennej. (Lub w przypadku typów referencyjnych może być zerowy.)
Eric Lippert
15
Jeśli chodzi o twój drugi punkt: C # miał już funkcję „stwórz zmienną, w którą możesz umieścić wszystko” - zawsze możesz zrobić zmienną typu obiektowego. Interesującą rzeczą dotyczącą dynamiki jest to, na co zwracasz uwagę w pierwszym akapicie: dynamika jest prawie identyczna z obiektem, z wyjątkiem tego, że analiza semantyczna jest odraczana do czasu wykonania, a analiza semantyczna jest wykonywana na typie wyrażenia w czasie wykonywania. (Przeważnie. Istnieją pewne wyjątki.)
Eric Lippert
18
Wydałem na to negatywny punkt, głównie dlatego, że domyślnie zaleca użycie słowa kluczowego do ogólnego użytku. Ma konkretnie ukierunkowany cel (dokładnie opisany w odpowiedzi Lassesa) i chociaż ta odpowiedź jest technicznie poprawna, prawdopodobnie sprowadzi deweloperów na manowce.
Ośmiobitowy Guru,
211
Słowo dynamickluczowe zostało dodane wraz z wieloma innymi nowymi funkcjami C # 4.0, aby ułatwić rozmowę z kodem, który mieszka lub pochodzi z innych środowisk wykonawczych, które mają różne interfejsy API.
Brać przykład.
Jeśli masz obiekt COM, taki jak Word.Applicationobiekt, i chcesz otworzyć dokument, metoda wykonania tego ma co najmniej 15 parametrów, z których większość jest opcjonalna.
Aby wywołać tę metodę, potrzebujesz czegoś takiego (upraszczam, to nie jest rzeczywisty kod):
Zwróć uwagę na te wszystkie argumenty? Musisz przekazać je, ponieważ C # przed wersją 4.0 nie zawierał opcjonalnych argumentów. W C # 4.0 interfejsy API COM zostały ułatwione dzięki wprowadzeniu:
Zobacz, o ile łatwiej to wygląda, o ile bardziej staje się czytelne?
Rozbijmy to na części:
named argument, can skip the rest
|
v
wordApplication.Documents.Open(@"C:\Test.docx",ReadOnly:true);^^||
notice no ref keyword, can pass
actual parameter values instead
Magia polega na tym, że kompilator C # wstrzykuje teraz niezbędny kod i pracuje z nowymi klasami w środowisku wykonawczym, aby wykonać prawie dokładnie to samo co wcześniej, ale składnia została przed tobą ukryta, teraz możesz skupić się na co , a nie tak bardzo jak . Anders Hejlsberg lubi mówić, że trzeba przywoływać różne „zaklęcia”, co jest swoistą kalamburą całej magii, w której zazwyczaj trzeba machać ręką (rękami) i wypowiadać magiczne słowa we właściwej kolejności aby uzyskać pewien rodzaj zaklęcia. Stary sposób API do komunikowania się z obiektami COM był bardzo duży, trzeba było przeskakiwać przez wiele obręczy, aby nakłonić kompilator do skompilowania kodu za ciebie.
Sprawy psują się w C # przed wersją 4.0, a nawet bardziej, jeśli próbujesz porozmawiać z obiektem COM, dla którego nie masz interfejsu lub klasy, wszystko, co masz, to IDispatchodwołanie.
Jeśli nie wiesz, co to jest, IDispatchjest w zasadzie odbiciem dla obiektów COM. Za pomocą IDispatchinterfejsu możesz zapytać obiekt „jaki jest numer identyfikacyjny metody znanej jako Save”, i zbudować tablice określonego typu zawierające wartości argumentów, a na końcu wywołać Invokemetodę IDispatchinterfejsu, aby wywołać metodę, przekazując wszystkie informacje, które udało ci się zebrać razem.
Powyższa metoda Save może wyglądać następująco (to zdecydowanie nie jest właściwy kod):
jest w zasadzie po prostu C # dogania VB pod względem ekspresyjności, ale robi to we właściwy sposób, umożliwiając rozszerzenie, nie tylko dla COM. Oczywiście jest to również dostępne dla VB.NET lub dowolnego innego języka zbudowanego na środowisku uruchomieniowym .NET.
Więcej informacji na temat IDispatchinterfejsu można znaleźć na Wikipedii: IDispatch, jeśli chcesz dowiedzieć się więcej na ten temat. To naprawdę krwawe rzeczy.
Co jednak, jeśli chcesz porozmawiać z obiektem Python? Istnieje inny interfejs API niż ten używany dla obiektów COM, a ponieważ obiekty Pythona również mają charakter dynamiczny, musisz skorzystać z magii odbicia, aby znaleźć odpowiednie metody wywoływania, ich parametry itp., Ale nie .NET odbicie, coś napisanego dla Pythona, zupełnie jak powyższy kod IDispatch, zupełnie inny.
A dla Ruby? Wciąż inny interfejs API.
JavaScript? Ta sama oferta, inne API również.
Dynamiczne słowo kluczowe składa się z dwóch rzeczy:
Nowe słowo kluczowe w C #, dynamic
Zestaw klas środowiska wykonawczego, które wiedzą, jak radzić sobie z różnymi typami obiektów, które implementują określony interfejs API dynamicwymagany przez słowo kluczowe, i odwzorowuje wywołania we właściwy sposób. Interfejs API jest nawet udokumentowany, więc jeśli masz obiekty pochodzące z środowiska wykonawczego, które nie są objęte, możesz je dodać.
Słowo dynamickluczowe nie ma jednak na celu zastąpienia żadnego istniejącego kodu tylko .NET. Jasne, możesz to zrobić, ale z tego powodu nie został dodany, a autorzy języka programowania C # z Anders Hejlsberg na czele, byli bardzo nieugięci, że nadal uważają C # za język mocno napisany na maszynie i nie poświęcą się ta zasada.
Oznacza to, że chociaż możesz napisać taki kod:
dynamic x =10;dynamic y =3.14;dynamic z ="test";dynamic k =true;dynamic l = x + y * z - k;
i niech to się skompiluje, nie miało to być rodzajem systemu typu magia, który wymyślił, co miałeś na myśli w czasie wykonywania.
Głównym celem było ułatwienie rozmowy z innymi typami obiektów.
W Internecie znajduje się mnóstwo materiałów na temat słowa kluczowego, zwolenników, przeciwników, dyskusji, rantów, pochwał itp.
Sugeruję zacząć od poniższych linków, a następnie google, aby uzyskać więcej:
Jest także przydatny oprócz COM dla internetowych interfejsów API JSON, w których struktura zdserializowanych obiektów JSON nie jest określona w języku C #. Na przykład metoda dekodowania System.Web.Helpers.Json zwraca obiekt dynamiczny .
Nie zgadzam się z nim, ale to kwestia opinii, a nie faktów. „Silnie wpisany” oznacza dla mnie, że kompilator wie w czasie kompilacji, który typ jest używany, a tym samym egzekwuje reguły ustawione wokół tych typów. Fakt, że możesz wybrać typ dynamiczny, który odracza sprawdzanie reguł i wiązanie do środowiska wykonawczego, nie oznacza dla mnie, że język jest słabo wpisany. Zwykle nie kontrastuję silnie pisanego z słabo pisanym, jednak zwykle porównuję go do pisania dynamicznego, takiego jak języki takie jak Python, gdzie wszystko jest kaczką, dopóki nie zaszczeka.
Lasse V. Karlsen
Jaki jest sens tej odpowiedzi? Połowa z nich dotyczy parametrów opcjonalnych i interfejsu IDispatch.
Xam
Właśnie dlatego dynamicdodano, aby wesprzeć inne ekosystemy w tym, jak można wywoływać metody refleksyjne, a także zapewnić rodzaj czarnej skrzynki dla struktur danych z udokumentowanym sposobem osiągnięcia tego.
Oto przykład mojego własnego zastosowania. Zamiast robić:
publicstaticMapDtoBaseCreateDto(ChartItem item){if(item isElevationPoint)returnCreateDtoImpl((ElevationPoint)item);if(item isMapPoint)returnCreateDtoImpl((MapPoint)item);if(item isMapPolyline)returnCreateDtoImpl((MapPolyline)item);//other subtypes followthrownewObjectNotFoundException("Counld not find suitable DTO for "+ item.GetType());}
Ty robisz:
publicstaticMapDtoBaseCreateDto(ChartItem item){returnCreateDtoImpl(item asdynamic);}privatestaticMapDtoBaseCreateDtoImpl(ChartItem item){thrownewObjectNotFoundException("Counld not find suitable DTO for "+ item.GetType());}privatestaticMapDtoBaseCreateDtoImpl(MapPoint item){returnnewMapPointDto(item);}privatestaticMapDtoBaseCreateDtoImpl(ElevationPoint item){returnnewElevationDto(item);}
Zauważ, że w pierwszym przypadku ElevationPointjest ona podklasą MapPointi jeśli nie zostanie umieszczona wcześniejMapPoint , nigdy nie zostanie osiągnięta. Nie dotyczy to dynamiki, ponieważ zostanie wywołana metoda najbliższego dopasowania.
Jak można się domyślić na podstawie kodu, ta funkcja przydała się, gdy wykonywałem tłumaczenie obiektów ChartItem na ich wersje możliwe do serializacji. Nie chciałem zanieczyszczać mojego kodu odwiedzającymi i nie chciałem również zanieczyszczać mojegoChartItem obiektów bezużytecznymi atrybutami specyficznymi dla serializacji.
Nie wiedziałem o tym przypadku użycia. W najlepszym razie trochę zuchwały. Zrzuci każdy analizator statyczny.
Kugel
2
@Kugel to prawda, ale nie nazwałbym tego hackem . Analiza statyczna jest dobra, ale nie pozwoliłbym, aby powstrzymała mnie od eleganckiego rozwiązania, w którym alternatywami są: naruszenie zasady otwartego zamknięcia (wzorzec odwiedzin) lub zwiększona złożoność cykliczna z przerażającym isstosem jeden na drugim.
Stelios Adamantidis
4
Masz opcję dopasowania wzoru do C # 7, nie?
Kugel
2
Cóż, operatory są w ten sposób o wiele tańsze (unikając podwójnego rzutowania) i otrzymujesz z powrotem analizę statyczną ;-) i wydajność.
Kugel
@idbrii proszę nie zmieniaj moich odpowiedzi. Dodaj komentarz, a wyjaśnię (w razie potrzeby), ponieważ nadal jestem aktywny w tej społeczności. Proszę również nie używać magic; nie ma czegoś takiego jak magia.
Stelios Adamantidis,
11
Ułatwia współdziałanie języków statycznych (CLR) z dynamicznymi (python, ruby ...) działającymi na DLR (środowisko uruchomieniowe języka dynamicznego), patrz MSDN :
Na przykład możesz użyć następującego kodu, aby zwiększyć licznik w XML w C #.
A zmiana wymagana przez VM dla dynamiki faktycznie ułatwia dynamiczne języki.
Dykam
2
@Dykam: Nie ma zmian w maszynie wirtualnej. DLR działa dobrze aż do .NET 2.0.
Jörg W Mittag
@ Jörg, tak, jest zmiana. DLR jest częściowo przepisany, ponieważ teraz maszyna wirtualna ma wbudowaną obsługę dynamicznego rozwiązywania problemów.
Dykam
Byłem trochę zbyt optymistyczny, badania wykazały, że zmiany nie były tak duże.
Dykam
4
Przykład zastosowania:
Zużywasz wiele klas, które mają właściwość komunalną „CreationDate”:
publicclassContact{// some propertiespublicDateTimeCreationDate{get;set;}}publicclassCompany{// some propertiespublicDateTimeCreationDate{get;set;}}publicclassOpportunity{// some propertiespublicDateTimeCreationDate{get;set;}}
Jeśli napiszesz metodę commun, która pobiera wartość właściwości „CreationDate”, będziesz musiał użyć refleksji:
Cyniczna odpowiedź, ale łatwo zbyt prawdziwa. Widziałem to po prostu w celu uniknięcia deklarowania struktur, w wyniku czego kod działa, jeśli wszystko jest w porządku, ale wysadza stos w nieprzewidywalny sposób, gdy tylko przeniesiesz swój ser.
AnthonyVO
Tak, zobaczysz to klasyczne cięcie narożne z wieloma innymi funkcjami językowymi. Nic dziwnego, że zobaczysz to tutaj.
Hawkeye4040,
1
Sprawdza się w czasie wykonywania, więc możesz zmienić typ, tak jak w JavaScript, na cokolwiek chcesz. Jest to uzasadnione:
dynamic i =12;
i ="text";
Możesz więc zmienić typ według potrzeb. Użyj go w ostateczności; jest to korzystne, ale słyszałem, że wiele dzieje się pod scenami pod względem generowanej IL, a to może mieć cenę za wydajność.
Z wahaniem powiedziałbym, że to „legalne”. Z pewnością się skompiluje, więc jako taki jest „legalnym kodem” w tym sensie, że kompilator go teraz skompiluje, a środowisko wykonawcze uruchomi go. Ale nigdy nie chciałbym widzieć tego konkretnego fragmentu kodu (lub czegoś podobnego do niego) w żadnym z utrzymywanych przeze mnie kodów, w przeciwnym razie byłoby to przestępstwo prawie odpalające.
Lasse V. Karlsen
6
Jasne, ale byłoby to „uzasadnione” za pomocą „obiektu” zamiast „dynamicznego”. Nie pokazałeś tutaj nic ciekawego na temat dynamiki.
Eric Lippert
W przypadku obiektu musisz rzucić go na odpowiedni typ, aby faktycznie wywołać dowolną z jego metod ... stracisz podpis; możesz wywoływać kod dowolną metodą bez błędu kompilacji, a także błędy w czasie wykonywania. Spieszyło mi się pisać, przepraszam, że nie sprecyzowałem. I @Lasse, zgodziłbym się i prawdopodobnie nie użyję dużo dynamiki.
Brian Mains
1
Przypadek użycia w ostateczności nie został wyjaśniony
denfromufa,
1
Najlepszym przypadkiem użycia zmiennych typu „dynamicznego” było dla mnie, gdy ostatnio pisałem warstwę dostępu do danych w ADO.NET ( używając SQLDataReader ), a kod wywoływał już zapisane procedury składowane. Istnieją setki tych starszych procedur przechowywanych, zawierających większość logiki biznesowej. Moja warstwa dostępu do danych musiała zwrócić jakieś ustrukturyzowane dane do warstwy logiki biznesowej, opartej na języku C #, aby wykonać pewne manipulacje ( chociaż nie ma prawie żadnych ). Każda procedura przechowywana zwraca inny zestaw danych ( kolumny tabeli ). Zamiast tworzyć dziesiątki klas lub struktur do przechowywania zwróconych danych i przekazywania ich do BLL, napisałem poniższy kod, który wygląda dość elegancko i schludnie.
publicstaticdynamicGetSomeData(ParameterDTO dto){dynamic result =null;stringSPName="a_legacy_stored_procedure";
using (SqlConnection connection =newSqlConnection(DataConnection.ConnectionString)){SqlCommand command =newSqlCommand(SPName, connection);
command.CommandType=System.Data.CommandType.StoredProcedure;
command.Parameters.Add(newSqlParameter("@empid", dto.EmpID));
command.Parameters.Add(newSqlParameter("@deptid", dto.DeptID));
connection.Open();
using (SqlDataReader reader = command.ExecuteReader()){while(reader.Read()){dynamic row =newExpandoObject();
row.EmpName= reader["EmpFullName"].ToString();
row.DeptName= reader["DeptName"].ToString();
row.AnotherColumn= reader["AnotherColumn"].ToString();
result = row;}}}return result;}
Możesz wywoływać w dynamicznych językach, takich jak CPython, używając pythonnet:
dynamic np = Py.Import("numpy")
Możesz zastosować rzutowanie na ogólne, dynamicgdy zastosujesz na nich operatory numeryczne. Zapewnia to bezpieczeństwo typu i pozwala uniknąć ograniczeń leków generycznych. To w istocie * pisanie kaczek:
Innym przykładem użycia do dynamicpisania są metody wirtualne, w których występuje problem z kowariancją lub kontrawariancją. Jednym z takich przykładów jest niesławna Clonemetoda, która zwraca obiekt tego samego typu, co obiekt, do którego został wywołany. Ten problem nie został w pełni rozwiązany za pomocą dynamicznego powrotu, ponieważ omija sprawdzanie typu statycznego, ale przynajmniej nie trzeba przez cały czas używać brzydkich rzutów, jak w przypadku zwykłego object. Innymi słowy, obsady stają się niejawne.
publicclass A
{// attributes and constructor herepublicvirtualdynamicClone(){var clone =new A();// Do more cloning stuff herereturn clone;}}publicclass B : A
{// more attributes and constructor herepublicoverridedynamicClone(){var clone =new B();// Do more cloning stuff herereturn clone;}}publicclassProgram{publicstaticvoidMain(){
A a =new A().Clone();// No cast needed here
B b =new B().Clone();// and here// do more stuff with a and b}}
Odpowiedzi:
Dynamiczne słowo kluczowe jest nowością w C # 4.0 i służy do informowania kompilatora, że typ zmiennej może się zmienić lub że nie jest znany do czasu uruchomienia. Pomyśl o tym, że może wchodzić w interakcje z przedmiotem bez rzucania go.
Uwaga: nie musieliśmy przesyłać ani deklarować klienta jako klienta typu. Ponieważ zadeklarowaliśmy, że jest dynamiczny, środowisko wykonawcze przejmuje, a następnie wyszukuje i ustawia dla nas właściwość FirstName. Teraz, oczywiście, kiedy używasz zmiennej dynamicznej, rezygnujesz z sprawdzania typu kompilatora. Oznacza to, że wywołanie cust.MissingMethod () zostanie skompilowane i nie zakończy się niepowodzeniem, dopóki nie zostanie uruchomione. Wynikiem tej operacji jest RuntimeBinderException, ponieważ MissingMethod nie jest zdefiniowany w klasie Customer.
Powyższy przykład pokazuje, jak działa dynamika podczas wywoływania metod i właściwości. Kolejną potężną (i potencjalnie niebezpieczną) funkcją jest możliwość ponownego wykorzystywania zmiennych dla różnych typów danych. Jestem pewien, że programiści Python, Ruby i Perl mogą wymyślić milion sposobów na skorzystanie z tego, ale używam C # tak długo, że wydaje mi się to „złe”.
OK, więc najprawdopodobniej nie będziesz pisać kodu tak jak powyżej. Może się jednak zdarzyć, że ponowne użycie zmiennych może się przydać lub wyczyścić brudny kawałek starszego kodu. Jednym prostym przypadkiem, w którym często się spotykam, jest ciągłe rzucanie między dziesiętną a podwójną.
Druga linia nie jest kompilowana, ponieważ 2.5 jest wpisany jako podwójny, a linia 3 nie jest kompilowana, ponieważ Math.Sqrt oczekuje podwójnej. Oczywiście wszystko, co musisz zrobić, to rzutować i / lub zmienić typ zmiennej, ale mogą zdarzyć się sytuacje, w których użycie dynamiki ma sens.
Czytaj więcej funkcji: http://www.codeproject.com/KB/cs/CSharp4Features.aspx
źródło
dynamic
in c # do rozwiązywania problemów, które można rozwiązać (być może nawet lepiej) za pomocą standardowych funkcji c # i pisania statycznego lub co najwyżej za pomocą wnioskowania typu (var
).dynamic
powinien być stosowany tylko w przypadku problemów z interoperacyjnością z DLR. Jeśli piszesz kod w języku statycznym, takim jak c #, zrób to i nie emuluj języka dynamicznego. To po prostu brzydkie.dynamic
zmiennych w swoim kodzie, gdzie ich nie potrzebujesz (jak w przykładzie z kwadratowym korzeniem), rezygnujesz z sprawdzania błędów podczas kompilacji; zamiast tego otrzymujesz możliwe błędy czasu wykonywania.Słowo
dynamic
kluczowe zostało dodane wraz z wieloma innymi nowymi funkcjami C # 4.0, aby ułatwić rozmowę z kodem, który mieszka lub pochodzi z innych środowisk wykonawczych, które mają różne interfejsy API.Brać przykład.
Jeśli masz obiekt COM, taki jak
Word.Application
obiekt, i chcesz otworzyć dokument, metoda wykonania tego ma co najmniej 15 parametrów, z których większość jest opcjonalna.Aby wywołać tę metodę, potrzebujesz czegoś takiego (upraszczam, to nie jest rzeczywisty kod):
Zwróć uwagę na te wszystkie argumenty? Musisz przekazać je, ponieważ C # przed wersją 4.0 nie zawierał opcjonalnych argumentów. W C # 4.0 interfejsy API COM zostały ułatwione dzięki wprowadzeniu:
ref
opcjonalne dla COM APINowa składnia powyższego wywołania to:
Zobacz, o ile łatwiej to wygląda, o ile bardziej staje się czytelne?
Rozbijmy to na części:
Magia polega na tym, że kompilator C # wstrzykuje teraz niezbędny kod i pracuje z nowymi klasami w środowisku wykonawczym, aby wykonać prawie dokładnie to samo co wcześniej, ale składnia została przed tobą ukryta, teraz możesz skupić się na co , a nie tak bardzo jak . Anders Hejlsberg lubi mówić, że trzeba przywoływać różne „zaklęcia”, co jest swoistą kalamburą całej magii, w której zazwyczaj trzeba machać ręką (rękami) i wypowiadać magiczne słowa we właściwej kolejności aby uzyskać pewien rodzaj zaklęcia. Stary sposób API do komunikowania się z obiektami COM był bardzo duży, trzeba było przeskakiwać przez wiele obręczy, aby nakłonić kompilator do skompilowania kodu za ciebie.
Sprawy psują się w C # przed wersją 4.0, a nawet bardziej, jeśli próbujesz porozmawiać z obiektem COM, dla którego nie masz interfejsu lub klasy, wszystko, co masz, to
IDispatch
odwołanie.Jeśli nie wiesz, co to jest,
IDispatch
jest w zasadzie odbiciem dla obiektów COM. Za pomocąIDispatch
interfejsu możesz zapytać obiekt „jaki jest numer identyfikacyjny metody znanej jako Save”, i zbudować tablice określonego typu zawierające wartości argumentów, a na końcu wywołaćInvoke
metodęIDispatch
interfejsu, aby wywołać metodę, przekazując wszystkie informacje, które udało ci się zebrać razem.Powyższa metoda Save może wyglądać następująco (to zdecydowanie nie jest właściwy kod):
Wszystko po to, by otworzyć dokument.
VB miał opcjonalne argumenty i wsparcie dla większości tego od razu po wyjęciu z pudełka, więc ten kod C #:
jest w zasadzie po prostu C # dogania VB pod względem ekspresyjności, ale robi to we właściwy sposób, umożliwiając rozszerzenie, nie tylko dla COM. Oczywiście jest to również dostępne dla VB.NET lub dowolnego innego języka zbudowanego na środowisku uruchomieniowym .NET.
Więcej informacji na temat
IDispatch
interfejsu można znaleźć na Wikipedii: IDispatch, jeśli chcesz dowiedzieć się więcej na ten temat. To naprawdę krwawe rzeczy.Co jednak, jeśli chcesz porozmawiać z obiektem Python? Istnieje inny interfejs API niż ten używany dla obiektów COM, a ponieważ obiekty Pythona również mają charakter dynamiczny, musisz skorzystać z magii odbicia, aby znaleźć odpowiednie metody wywoływania, ich parametry itp., Ale nie .NET odbicie, coś napisanego dla Pythona, zupełnie jak powyższy kod IDispatch, zupełnie inny.
A dla Ruby? Wciąż inny interfejs API.
JavaScript? Ta sama oferta, inne API również.
Dynamiczne słowo kluczowe składa się z dwóch rzeczy:
dynamic
dynamic
wymagany przez słowo kluczowe, i odwzorowuje wywołania we właściwy sposób. Interfejs API jest nawet udokumentowany, więc jeśli masz obiekty pochodzące z środowiska wykonawczego, które nie są objęte, możesz je dodać.Słowo
dynamic
kluczowe nie ma jednak na celu zastąpienia żadnego istniejącego kodu tylko .NET. Jasne, możesz to zrobić, ale z tego powodu nie został dodany, a autorzy języka programowania C # z Anders Hejlsberg na czele, byli bardzo nieugięci, że nadal uważają C # za język mocno napisany na maszynie i nie poświęcą się ta zasada.Oznacza to, że chociaż możesz napisać taki kod:
i niech to się skompiluje, nie miało to być rodzajem systemu typu magia, który wymyślił, co miałeś na myśli w czasie wykonywania.
Głównym celem było ułatwienie rozmowy z innymi typami obiektów.
W Internecie znajduje się mnóstwo materiałów na temat słowa kluczowego, zwolenników, przeciwników, dyskusji, rantów, pochwał itp.
Sugeruję zacząć od poniższych linków, a następnie google, aby uzyskać więcej:
źródło
dynamic
dodano, aby wesprzeć inne ekosystemy w tym, jak można wywoływać metody refleksyjne, a także zapewnić rodzaj czarnej skrzynki dla struktur danych z udokumentowanym sposobem osiągnięcia tego.Dziwi mnie, że nikt nie wspomniał o wysyłce wielokrotnej . Zwykłym sposobem obejścia tego problemu jest wzorzec użytkownika i nie zawsze jest to możliwe, więc kończy się na stosach
is
czeków.Oto przykład mojego własnego zastosowania. Zamiast robić:
Ty robisz:
Zauważ, że w pierwszym przypadku
ElevationPoint
jest ona podklasąMapPoint
i jeśli nie zostanie umieszczona wcześniejMapPoint
, nigdy nie zostanie osiągnięta. Nie dotyczy to dynamiki, ponieważ zostanie wywołana metoda najbliższego dopasowania.Jak można się domyślić na podstawie kodu, ta funkcja przydała się, gdy wykonywałem tłumaczenie obiektów ChartItem na ich wersje możliwe do serializacji. Nie chciałem zanieczyszczać mojego kodu odwiedzającymi i nie chciałem również zanieczyszczać mojego
ChartItem
obiektów bezużytecznymi atrybutami specyficznymi dla serializacji.źródło
is
stosem jeden na drugim.magic
; nie ma czegoś takiego jak magia.Ułatwia współdziałanie języków statycznych (CLR) z dynamicznymi (python, ruby ...) działającymi na DLR (środowisko uruchomieniowe języka dynamicznego), patrz MSDN :
MSDN wymienia następujące zalety:
Aby uzyskać więcej informacji, zobacz MSDN .
źródło
Przykład zastosowania:
Zużywasz wiele klas, które mają właściwość komunalną „CreationDate”:
Jeśli napiszesz metodę commun, która pobiera wartość właściwości „CreationDate”, będziesz musiał użyć refleksji:
Dzięki koncepcji „dynamicznej” kod jest znacznie bardziej elegancki:
źródło
COM interop. Szczególnie Nieznany. Został zaprojektowany specjalnie do tego.
źródło
Będzie głównie używany przez ofiary RAD i Pythona do niszczenia jakości kodu, IntelliSense i wykrywania błędów kompilacji czasu.
źródło
Sprawdza się w czasie wykonywania, więc możesz zmienić typ, tak jak w JavaScript, na cokolwiek chcesz. Jest to uzasadnione:
Możesz więc zmienić typ według potrzeb. Użyj go w ostateczności; jest to korzystne, ale słyszałem, że wiele dzieje się pod scenami pod względem generowanej IL, a to może mieć cenę za wydajność.
źródło
Najlepszym przypadkiem użycia zmiennych typu „dynamicznego” było dla mnie, gdy ostatnio pisałem warstwę dostępu do danych w ADO.NET ( używając SQLDataReader ), a kod wywoływał już zapisane procedury składowane. Istnieją setki tych starszych procedur przechowywanych, zawierających większość logiki biznesowej. Moja warstwa dostępu do danych musiała zwrócić jakieś ustrukturyzowane dane do warstwy logiki biznesowej, opartej na języku C #, aby wykonać pewne manipulacje ( chociaż nie ma prawie żadnych ). Każda procedura przechowywana zwraca inny zestaw danych ( kolumny tabeli ). Zamiast tworzyć dziesiątki klas lub struktur do przechowywania zwróconych danych i przekazywania ich do BLL, napisałem poniższy kod, który wygląda dość elegancko i schludnie.
źródło
dynamic np = Py.Import("numpy")
dynamic
gdy zastosujesz na nich operatory numeryczne. Zapewnia to bezpieczeństwo typu i pozwala uniknąć ograniczeń leków generycznych. To w istocie * pisanie kaczek:T y = x * (dynamic)x
, gdzietypeof(x) is T
źródło
Innym przykładem użycia do
dynamic
pisania są metody wirtualne, w których występuje problem z kowariancją lub kontrawariancją. Jednym z takich przykładów jest niesławnaClone
metoda, która zwraca obiekt tego samego typu, co obiekt, do którego został wywołany. Ten problem nie został w pełni rozwiązany za pomocą dynamicznego powrotu, ponieważ omija sprawdzanie typu statycznego, ale przynajmniej nie trzeba przez cały czas używać brzydkich rzutów, jak w przypadku zwykłegoobject
. Innymi słowy, obsady stają się niejawne.źródło