Zmiany w odbiciu wywołują wyjątki interfejsu API
Wyjątki zgłaszane podczas wywoływania interfejsów API wywołania odbicia uległy zmianie.
Poprzednie zachowanie
Wcześniej, gdy wywołana metoda zwracająca wartość przy użyciu odwołania zwróciła
null
wartość , NullReferenceException element został zgłoszony.W przypadku konstruktorów zostały zgłoszone następujące wyjątki:
- Wyjątki przejściowe, w tym OutOfMemoryException.
- Wartość ujemna OverflowException została przekazana dla parametru długości tablicy.
Gdy
null
przekazano parametr byref-like bezref
modyfikatora (czyli przekazywanego przez wartość), nie zgłoszono wyjątku, a środowisko uruchomieniowe zastąpiło wartość domyślną wartości null.
Nowe zachowanie
Począwszy od platformy .NET 7:
Zamiast zgłaszać wyjątek źródłowy (w tym NullReferenceException i wymienione w poprzednim zachowaniu), TargetInvocationException jest zgłaszany we wszystkich przypadkach po zweryfikowaniu początkowych
Invoke()
parametrówOutOfMemoryException. Wyjątek wewnętrzny zawiera wyjątek źródłowy.NotSupportedExceptionparametr jest zgłaszany, gdy
null
jest przekazywany dla parametru przypominającego byref, gdy parametr jest zadeklarowany jako "by value" (czyli nieref
ma modyfikatora). W przypadku powiązanego przypadku, gdy parametr jest przekazywany przez odwołanie (tj. maref
modyfikator), poprzednie i nowe zachowanie są takie same: NotSupportedException jest zgłaszany.
Wprowadzona wersja
.NET 7
Typ zmiany powodującej niezgodność
Ta zmiana może mieć wpływ na zgodność binarną.
Przyczyna wprowadzenia zmiany
Zgłaszanie TargetInvocationException zamiast wyjątku źródłowego sprawia, że środowisko jest bardziej spójne. Prawidłowo warstwuje wyjątki spowodowane weryfikacją parametrów przychodzących (które nie są opakowane TargetInvocationExceptionz ) w porównaniu z wyjątkami zgłaszanymi z powodu implementacji metody docelowej (które są opakowane). Spójne reguły zapewniają bardziej spójne środowiska w różnych implementacjach środowiska CLR i interfejsów Invoke
API.
Zmiana, która ma być zgłaszanaNotSupportedException, gdy typ przypominający byref jest przekazywany do Invoke()
interfejsu API, naprawia nadzór nad oryginalną implementacją, która nie zgłosiła. Oryginalna implementacja dała wygląd obsługiwany ref struct
przez Invoke()
interfejsy API, gdy nie są obsługiwane. Ponieważ bieżące Invoke()
interfejsy API są używane System.Object dla typów parametrów i ref struct
nie można wpisać typu do System.Object, jest to nieobsługiwany scenariusz.
Zalecana akcja
Jeśli nie używasz BindingFlags.DoNotWrapExceptions funkcji podczas wywoływania Invoke()
metody i masz catch
instrukcje dotyczące Invoke()
interfejsów API dla wyjątków innych niż TargetInvocationException, rozważ zmianę lub usunięcie tych catch
instrukcji. Inne wyjątki nie będą już zgłaszane w wyniku wywołania. Jeśli jednak przechwytujesz wyjątki z weryfikacji argumentów, które mają miejsce przed podjęciem próby wywołania metody docelowej, należy zachować te catch
instrukcje. Nieprawidłowe argumenty, które są weryfikowane przed podjęciem próby wywołania, są zgłaszane bez zawijania TargetInvocationException i nie zmieniły semantyki.
Rozważ użycie BindingFlags.DoNotWrapExceptions metody , aby TargetInvocationException nigdy nie zostało to rzucone. W takim przypadku wyjątek źródłowy nie zostanie opakowany przez element TargetInvocationException. W większości przypadków nie opakowywanie wyjątku zwiększa prawdopodobieństwo diagnozowania rzeczywistego problemu, ponieważ nie wszystkie narzędzia raportowania wyjątków wyświetlają wyjątek wewnętrzny. Ponadto przy użyciu metody BindingFlags.DoNotWrapExceptionszostaną zgłoszone te same wyjątki, co podczas bezpośredniego wywoływania metody (bez odbicia). Jest to pożądane w większości przypadków, ponieważ wybór, czy odbicie jest używane, czy nie może być dowolne lub szczegóły implementacji, które nie muszą być uwidocznione w obiekcie wywołującym.
W rzadkich przypadkach, gdy musisz przekazać wartość domyślną do metody poprzez odbicie zawierające parametr przypominający byref, który jest przekazywany "według wartości", można dodać metodę otoki, która pomija parametr i wywołuje metodę docelową z wartością domyślną dla tego parametru.
Dotyczy interfejsów API
- System.Reflection.MethodBase.Invoke(Object, Object[])
- System.Reflection.MethodBase.Invoke(Object, BindingFlags, Binder, Object[], CultureInfo)
- System.Reflection.ConstructorInfo.Invoke(Object[])
- System.Reflection.ConstructorInfo.Invoke(BindingFlags, Binder, Object[], CultureInfo)
- System.Reflection.PropertyInfo.GetValue(Object)
- System.Reflection.PropertyInfo.GetValue(Object, Object[])
- System.Reflection.PropertyInfo.GetValue(Object, BindingFlags, Binder, Object[], CultureInfo)
- System.Reflection.PropertyInfo.SetValue(Object, Object)
- System.Reflection.PropertyInfo.SetValue(Object, Object, Object[])
- System.Reflection.PropertyInfo.SetValue(Object, Object, BindingFlags, Binder, Object[], CultureInfo)
- System.Reflection.Emit.DynamicMethod.Invoke(Object, BindingFlags, Binder, Object[], CultureInfo)
- System.Activator.CreateInstance(Type, Object[])
- System.Activator.CreateInstance(Type, Object[], Object[])
- System.Activator.CreateInstance(Type, BindingFlags, Binder, Object[], CultureInfo)
- System.Activator.CreateInstance(Type, BindingFlags, Binder, Object[], CultureInfo, Object[])
- System.Activator.CreateInstance(String, String, Boolean, BindingFlags, Binder, Object[], CultureInfo, Object[])