Dlaczego rzucenie dynamiki typu obiekt do obiektu rzuca wyjątek null reference?
Mam następującą funkcję:
public static T TryGetArrayValue<T>(object[] array_, int index_)
{
... //some checking goes up here not relevant to question
dynamic boxed = array_[index_];
return (T)boxed;
}
Kiedy nazywam to w następujący sposób,
object a = new object();
object v = TUtils.TryGetArrayValue<object>(new object[] { a }, 0);
(T)boxed
rzuca wyjątek null reference.
Każdy inny typ, który tam umieściłem, poza" obiektem", działa idealnie.
Jakieś pomysły, co to jest i dlaczego rzuca wyjątek?
Edytuj: Powodem, dla którego używam dynamic, jest unikanie WYJĄTKÓW podczas konwersji typów, na przykład:
double a = 123;
int v = TUtils.TryGetArrayValue<int>(new object[] { a }, 0);
4 answers
Zgadzam się z innymi odpowiedzialnymi, którzy twierdzą, że to wygląda jak pluskwa. W szczególności wydaje się, że jest to błąd w warstwie wiążącej C# runtime, chociaż nie zbadałem go dokładnie.
Przepraszam za błąd. Zgłoszę to do zespołu testującego C# 5 i zobaczymy, czy zostało już zgłoszone i naprawione w C # 5. (Odtwarza się w ostatniej wersji beta, więc jest mało prawdopodobne, że został już zgłoszony i naprawiony.) Jeśli nie, jest mało prawdopodobne, aby poprawka trafiła do finalnego wydania. W takim przypadku rozważymy to dla ewentualnego zwolnienia serwisowego.
Dzięki za zwrócenie na to uwagi. Jeśli masz ochotę wprowadzić problem z połączeniem, aby go śledzić, nie krępuj się tego zrobić i dołącz link do tego pytania Stoskoverflow. Jeśli nie, nie ma problemu; zespół testowy będzie wiedział o tym tak czy inaczej.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-29 19:46:52
Jest to problem z tym, jak działa dynamic - binder runtime ma problem z konwersjami z System.Object
, ale w praktyce tak naprawdę nie jest problemem.
Podejrzewam, że to dlatego, że dynamic
, w czasie wykonywania, jest sobą zawsze System.Object
. Specyfikacja języka C# w wersji 4.7 stwierdza: "Typ dynamic jest nieodróżnialny od obiektu w czasie wykonywania."Jako taki, każdy obiekt używany jako dynamiczny jest po prostu przechowywany jako obiekt.
Kiedy umieścisz rzeczywistą instancję System.Object
w dynamice, coś jest występuje w rozdzielczości wiązania runtime, która powoduje wyjątek null reference.
Jednak każdy inny typ , który nie jest System.Object
działa - nawet typy referencyjne i tym podobne, bez wad. W związku z tym powinno to zapewnić właściwe zachowanie, ponieważ naprawdę nie ma powodów, aby utworzyć instancję System.Object
, która byłaby przekazywana - zawsze potrzebujesz podklasy z innymi informacjami o typie.
Jak tylko użyjesz dowolnego "prawdziwego" typu, działa to dobrze. Na exmaple, następujące prace, mimo że jest przekazywana i traktowana jako Object
:
public class Program
{
public static T TryGetArrayValue<T>(object[] array_, int index_)
{
dynamic boxed = array_[index_];
return (T)boxed;
}
private static void Main()
{
int p = 3;
object a = p;
var objects = new[] { a, 4.5 };
// This works now, since the object is pointing to a class instance
object v = TryGetArrayValue<object>(objects, 0);
Console.WriteLine(v);
// These both also work fine...
double d = TryGetArrayValue<double>(objects, 1);
Console.WriteLine(d);
// Even the "automatic" int conversion works now
int i = TryGetArrayValue<int>(objects, 1);
Console.WriteLine(i);
Console.ReadKey();
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-29 19:18:06
To jest naprawdę dziwne zachowanie i rzeczywiście wygląda jak błąd w implementacji dynamic
. Odkryłem, że ta odmiana nie wyrzuca wyjątku i rzeczywiście zwraca obiekt:
public static T TryGetArrayValue<T>(object[] array, int index) where T : class
{
dynamic boxed = array[index];
return boxed as T;
}
Zauważ, że musiałem dodać ogólne ograniczenie w podpisie metody, ponieważ operator as
działa tylko wtedy, gdy T
jest typem odniesienia.
Jeśli szukasz obejścia, możesz użyć tego (I Wiem, że jest brzydki):
public static T TryGetArrayValue<T>(object[] array, int index)
{
dynamic boxed = array[index];
if (typeof(T) == typeof(object))
return (T)(boxed as object);
return (T)boxed;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-29 19:27:58
Ma to coś wspólnego ze słowem kluczowym dynamic. Jeśli zmienię Typ Na t dla pudełka to działa.
static void Main(string[] args)
{
object a = new object();
object v = TryGetArrayValue<object>(new object[] { a }, 0);
Console.ReadLine();
}
public static T TryGetArrayValue<T>(object[] array_, int index_)
{
T boxed = (T)array_[index_];
return boxed;
}
Czy Jest jakiś szczególny powód, dla którego używasz dynamic? Naprawdę nie potrzebujesz go w tym przypadku, ponieważ wiesz, jaki typ jest wcześniej. Jeśli spojrzysz, w Twojej wersji Typ pudełka nie jest obiektowy, ale jest dynamiczny{obiekt} , co może być problemem podczas próby rzucenia na obiekt. Jeśli spojrzysz na tę wersję, którą opublikowałem, otrzymasz typ obiektu i brak błędów.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-29 19:07:31