2012-04-13 7 views
8

Mam pole, które jest typu "obiekt". Kiedy sprawdzam to w oknie Watch wizualnego studia, widzę jego Object [] i kiedy wierci się w elementach widzę każdy element jest ciągiem.Dlaczego nie mogę przekonwertować obiektu (który jest naprawdę obiektem []) na ciąg []?

Ale gdy próbuję oddać to do string [] otrzymuję ten błąd:

Cannot cast 'MyObject' (which has an actual type of 'object[]') to 'string[]' string[]

jakiegokolwiek powodu, dlaczego nie może tego zrobić obsadę? Jaki jest najlepszy sposób konwersji tego obiektu na tablicę ciągów znaków?

+0

Jak rzucasz swoją tablicą? Jako całość? Musisz rzucić każdy element swojej tablicy indywidualnie. – Msonic

+0

Tak, wyraźnie rzuca to jako całość. –

+1

Wariancja układu odniesienia jest odwrotna; możesz rzucić coś, co jest ** faktycznie ** a string [] 'jako' object [] ', ale aby pójść w inny sposób musi to być' string [] ' –

Odpowiedz

16
string[] newarr = Array.ConvertAll(objects, s => (string)s); 

--EDIT--

odkąd powiedział mam object (wiedząc, że jest to rzeczywiście object[])

string[] newarr = Array.ConvertAll((object[])objects, s => (string)s); 
+0

to nie wydaje się kompilować. . pojawia się błąd: nie można wywnioskować typu wnioskowania. . . – leora

+0

@leora zobacz zaktualizowaną odpowiedź. –

-1

można przekonwertować prawdziwystring[] do object[].

To Array covariance

można znaleźć wyraźny przykład w linku.

+0

@downvoter: czy chcesz wyjaśnić? – Tigran

+0

nie mój d/v, ale może b/c nie podałeś przykładu –

0
object[] original = new object[]{"1", "2"}; 
//some code in between here 
object obj = original ; 
object[] objArray = (object[])obj; 
string[] newArray = new string[objArray.Length]; 
for(int i = 0; i < newArray; i++) 
{ 
    newArray[i] = (string)objArray[i]; 
} 

Inne odpowiedzi pokazują ci szybsze/krótsze sposoby konwersji. Tak to napisałem, ponieważ pokazuje, co naprawdę się dzieje i co musi się wydarzyć. Powinieneś użyć jednej z prostszych metod w swoim rzeczywistym kodzie produkcyjnym.

+0

hmm. . z jakiegoś powodu twoje rozwiązanie jest jedyne, które kompiluje i działa dla mnie. . – leora

+0

@leora Większość pozostałych rozwiązała część problemu, ale nie całą sprawę. Rozwiązali tę część bardziej czysto/elegancko. Jak już powiedziałem, ten kod ma na celu pokazać, co musi się wydarzyć, nawet jeśli istnieje metoda biblioteki, która robi dla ciebie połowę. – Servy

+0

@Servy 'ale nie wszystko" jesteś pewien? ". –

-1

Należy odlać każdy element z kolekcji, a nie sam zbiór.

object[] ovalues = new object[] { "alpha", "beta" }; 
string[] svalues = ovalues.Cast<string>().ToArray(); 
+0

Nie mam obiektu []. .i ma tylko obiekt. . biorąc pod uwagę, że otrzymuję komunikat "Nie można rozwiązać Cast" – leora

+0

@leora 'using System.Linq;' –

+0

hmm. . . już mam to odniesienie. . . – leora

23

Jest to szczególnie myląca funkcja języka C#. Oto oferta.

Podczas tej dyskusji zakładamy, że typ elementu tablicy jest typem odniesienia, a nie typem wartości.

C# obsługuje niebezpieczną kowariancję tablicową. Oznacza to, że jeśli masz tablicę ciąg, można przekonwertować je do tablicy obiektu, ponieważ łańcuch można przekształcić do obiektu:

string[] a1 = { "hello", "goodbye" }; 
object[] a2 = a1; // Legal 

Jeśli następnie postarać się o element z A2 to działa:

object o3 = a2[0]; 

to legalne bo a2[0] jest naprawdę a1[0], który jest ciągiem znaków, którą można przekształcić w obiekt.

Jeśli jednak próbować zapisu do tablicy, a następnie dostaniesz błąd przy starcie:

a2[0] = new object(); 

To nie w czasie wykonywania, ponieważ a2 jest naprawdę tablicą łańcuchów, i nie można wstawić nie-ciągu w tablicę łańcuchów.

Więc C# jest już potwornie zepsute; możliwe jest napisanie programu, który kompiluje i wygląda normalnie, ale nagle ulega awarii z wyjątkiem typu w czasie wykonywania, ponieważ próbowałeś umieścić obiekt w tablicy obiektów, która nie jest tak naprawdę tablicą obiektów.

Funkcja, której potrzebujesz, to , jeszcze bardziej zepsuta niż ta, a dzięki uprzejmości C# nie obsługuje jej. Funkcja chcesz to:

object[] a4 = { "Hello" }; 
string[] a5 = a4; 

To byłoby niebezpieczne tablica kontrawariancja. Łamie strasznie tak:

a4[0] = new Customer(); // Perfectly legal 
string s6 = a5[0]; 

A teraz po prostu skopiowany Klientowi do zmiennej typu ciąg.

Powinieneś unikać wszelkiego rodzaju macierzy kowariancji lub kontrawariancji; Tablica wariancji jest, jak już odkryłeś, niezgodna z prawem, a kowariancja tablicowa tworzy w twoim programie mało bomb czasowych, które niespodziewanie znikają. Przygotuj tablice odpowiedniego typu.

+1

Zgadzam się z większością tego, co mówisz, ale nie zgadzam się, że sprzeczność tablic jest jeszcze bardziej złamana niż kowariancja tablicowa - wydają się one idealnie podwójnymi sytuacjami. Dzięki contrawariacie macierzy można odczytywać i zapisywać do tablicy obiektów, pisać do tablicy łańcuchów i czytać z tablicy łańcuchów, o ile obiekt innego typu nie został zapisany w tej lokalizacji przez tablicę obiektów. Za pomocą kowariancji można odczytywać i zapisywać w tablicy łańcuchów, czytać z tablicy obiektów i pisać do tablicy obiektów, o ile wstawiasz ciąg znaków w tej lokalizacji. – kvb

+4

@kvb: Rozumiem twój punkt widzenia. Twierdzę, że jest on "jeszcze bardziej zepsuty", ponieważ w przypadku kowariancji zepsuty scenariusz kończy się niepowodzeniem: konwersja po którym następuje zapis. Ale ponieważ wiele osób używa tablic jako * efektywnie * tylko do odczytu tablice - piszą tylko wtedy, gdy tablica jest tworzona - nie ma konwersji, a następnie następuje zapis, następuje tylko konwersja, po której następuje odczyt. Oznacza to, że może * tylko * zepsuć, jeśli po konwersji nastąpił * zapis *. Ale przypadek przeciwstawny może się włamać * dowolny * czytać po konwersji; tablica mogła nie być wszystkimi ciągami na początek! –

0

Zasada programowania obiektowego jest -

„Klasa pochodna może być zawsze typu lanego do klasy bazowej” I „klasy bazowej może być lanego do klasy pochodnej tylko jeśli bieżąca instancja że klasa bazowa hold off jest faktycznie pochodną klasy "

np. (A i B jest baza pochodzi)

A a = new B(); // legal; 
B b = (B) a ; // legal as "a" is actually B (in first statement) 

nielegalne:>

A a = new A(); 
B b = (B) a; // not legal as "a" is A only. 

To samo stosuje się do obiektów i klas String. Obiekt jest klasą podstawową, a łańcuch jest klasą pochodną.

Powiązane problemy