2012-11-20 7 views
5

Biorąc pod uwagę następujący kod C#:Typ wnioskowania w C# nie działa?

var a = new[] {"123", "321", 1}; //no best type found for implicitly typed array 

i jego odpowiednik w VB.NET:

Dim a = {"123", "321", 1} 'no errors 

Wydaje się, że VB.NET jest w stanie prawidłowo wywnioskować typ a = Object(), podczas gdy C# narzeka do czasu powyższego jest ustalona na:

var a = new object[] {"123", "321", 1}; 

Czy istnieje sposób, aby typ automatycznego wnioskowania w języku C# dla powyższego scenariusza?

EDIT: Ciekawa obserwacja po gry z różnych typów w C# piaskownicy - typ jest poprawnie wywnioskować, czy wszystkie elementy mają wspólnego rodzica w drzewie dziedziczenia, a rodzic jest nieObject, czy elementy mogą być odlewane w szerszy typ (bez utraty precyzji, na przykład Integer -> Double). Tak więc oba te będą pracować:

var a = new[] {1, 1.0}; //will infer double[] 
var a = new[] {new A(), new B()}; //will infer A[], if B inherits from A 

myślę, że to zachowanie jest niezgodne z C#, ponieważ wszystkie typy dziedziczą Object, więc to nie jest o wiele inny przodek niż jakikolwiek inny rodzaj. Jest to prawdopodobnie projekt wstępny, więc nie ma sensu dyskutować, ale jeśli znasz przyczynę, byłoby interesujące wiedzieć, dlaczego.

+0

prostu ciekawi, można byłoby lepiej z użyciem znakowanego przedmiotu zamiast pozbawionym typu tablicy? – CookieOfFortune

+0

@ CookieOfFortune: Czasami muszę napisać szybki i zabrudzony kod, głównie z powodów prototypowania, często by pomóc innym ludziom na SO. Tworzenie obiektu do tego celu nie jest możliwe. – Neolisk

+0

Przepraszam, miałem na myśli anonimowy obiekt: var a = new {Str1 = "123", Str2 = "321", AnInteger = 1}; – CookieOfFortune

Odpowiedz

9

Nie. Pseudo-typowe tablice w języku C# wymagają, aby typ jeden wyrażeń w inicjatorze macierzy był typu docelowego. Zasadniczo kompilator próbuje znaleźć dokładnie jeden typ elementu, aby wszystkie inne typy mogły zostać do niego przekonwertowane.

Można rzucać żadnego elementów do object przedmiotu:

var a = new[] { (object) "123", "321", 1}; 

... ale równie dobrze można po prostu użyć wyraźnie wpisane inicjatora tablicy:

var a = new object[] {"123", "321", 1}; 

Or w przypadkach, w których naprawdę jest zadeklarowanie zmiennej w tym samym czasie:

object[] a = {"123", "321", 1}; 
+0

Wystarczająco fair. Dziękuję za dokładne wyjaśnienie. – Neolisk

2

Nie. Możesz jednak sprawić, aby VB zachowywało się bardziej jak C#, używając opcji Option Jawna włączona, Opcja ścisła włączona i Opcja wnioskowania wyłączona.

Best Practices: Option Infer

+0

Czy mogę sprawić, aby C# zachowywało się bardziej jak VB? – Neolisk

+2

+1 @Josh C: Nie powiedziałbym "możesz", ale "musisz!" @Neolisk: użyj nowego _dynamicznego_ słowa kluczowego 'dynamic [] k = {" 123 "," 1 ", 1};" Teraz masz "coś" ... – igrimpe

+0

+1 Opcja Jawna ** musi ** być na! Opcja Strict powinna ** prawie zawsze ** być włączona. Ale możesz chcieć opuścić Option Infer On inaczej nie możesz użyć LINQ. – MarkJ

1

W języku C# można użyć dynamic: dynamic[] k = { "1", 2, "3" };

To nie naśladować VB zachowanie completey, choć. dynamic[] k = { "1", "2", "3" }; nadal daje tablicę obiektów, podczas gdy w VB otrzymujesz tablicę ciągów.

I oczywiście:

dynamic[] k = { "1", "3", "3" }; 
int i = k[0].I_do_not_exist(); 

kompiluje bez problemu, ale najprawdopodobniej nie powiedzie marnie;)

+0

+1 za miłą alternatywę. – Neolisk