V jazyce C #, proč nemůže List <string> object být uloženy v seznamu <object> proměnné

hlasů
76

Zdá se, že objekt Seznam nemůže být uložen v proměnné seznam v jazyce C #, a ani nemůže být explicitně cast tímto způsobem.

List<string> sl = new List<string>();
List<object> ol;
ol = sl;

Výsledky v Nelze implicitně převést typ System.Collections.Generic.List<string>naSystem.Collections.Generic.List<object>

A pak...

List<string> sl = new List<string>();
List<object> ol;
ol = (List<object>)sl;

Výsledky v nelze převést typ System.Collections.Generic.List<string>naSystem.Collections.Generic.List<object>

Samozřejmě, můžete to udělat vše, co vytažením ze seznamu řetězců a jeho uvedení zpět do jednoho po druhém, ale je to poněkud spletitý řešení.

Položena 09/08/2008 v 03:32
zdroj uživatelem
V jiných jazycích...                            


14 odpovědí

hlasů
35

Pokud používáte .NET 3.5 se podívat na způsob Enumerable.Cast. Je to metoda prodloužení, takže si můžete volat přímo na seznamu.

List<string> sl = new List<string>();
IEnumerable<object> ol;
ol = sl.Cast<object>();

Není to přesně to, co jste chtěl, ale měl by stačit.

Edit: Jak poznamenal Zooba, pak můžete volat ol.ToList () se zobrazí seznam

Odpovězeno 09/08/2008 v 04:07
zdroj uživatelem

hlasů
35

Přemýšlejte o tom tímto způsobem, pokud jste měli něco takového herce, a potom přidat objekt typu Foo na seznam, seznam řetězců již není konzistentní. Pokud byste měli opakovat první odkaz, měli byste dostat výjimku class cast, protože jakmile narazí na instance Foo se Foo nelze převést na řetězec!

Jako vedlejší poznámku, myslím, že by bylo mnohem významnější, zda můžete nebo nemůžete dělat zpětného obsazení:

List<object> ol = new List<object>();
List<string> sl;
sl = (List<string>)ol;

Osobně jsem nepoužil C # ve chvíli, takže nevím, jestli je to legální, ale takovéhle obsazení je ve skutečnosti (potenciálně) užitečné. V tomto případě budete z obecnějšího třídy (objekt) na konkrétnější třídy (String), která sahá od všeobecného jeden. Tímto způsobem, pokud přidáte do seznamu řetězců, nejste porušují seznam objektů.

Ví někdo, nebo můžete otestovat, zda tato cast je legální v C #?

Odpovězeno 09/08/2008 v 03:50
zdroj uživatelem

hlasů
14

Nemůžete házet mezi generickými typy s různými parametry typu. Specializované generické typy netvoří součást stejného dědictví stromu, a tak jsou nesouvisející druhy.

K tomu pre-NET 3.5:

List<string> sl = new List<string>();
// Add strings to sl

List<object> ol = new List<object>();

foreach(string s in sl)
{
    ol.Add((object)s);  // The cast is performed implicitly even if omitted
}

Pomocí LINQ:

var sl = new List<string>();
// Add strings to sl

var ol = new List<object>(sl.Cast<object>());

// OR
var ol = sl.Cast<object>().ToList();

// OR (note that the cast to object here is required)
var ol = sl.Select(s => (object)s).ToList();
Odpovězeno 10/08/2008 v 12:54
zdroj uživatelem

hlasů
12

Důvodem je skutečnost, že obecný třídu rád List<>je pro většinu účelů, zpracuje externě jako normální třídy. například, když říkáte List<string>(), že kompilátor říká ListString()(která obsahuje řetězce). [Technické folk: jedná se o velmi prostý-anglicko-ified verze toho, co se děje]

V důsledku toho je samozřejmě kompilátor nemůže být dost chytrý, aby převést ListString na ListObject litím položky svého vnitřního sbírky.

To je důvod, proč tam je rozšíření metody IEnumerable jako je převod (), které vám umožní snadno dodat konverze pro položky uložené v kolekci, které by mohly být stejně jednoduché jako odlitek z jednoho do druhého.

Odpovězeno 09/08/2008 v 03:38
zdroj uživatelem

hlasů
6

To má hodně co do činění s kovariance, např generické typy jsou považovány za parametry, a v případě, že parametry nejsou správně vyřešit konkrétnějšího typu pak operace se nezdaří. Důsledkem takového je, že si opravdu nemůže házet do obecnějšího typu, jako je objekt. A jak uvedl Rex, objekt seznamu není převést každý objekt pro vás.

Možná budete chtít zkusit ff kód namísto:

List<string> sl = new List<string>();
//populate sl
List<object> ol = new List<object>(sl);

nebo:

List<object> ol = new List<object>();
ol.AddRange(sl);

ol bude (teoreticky) zkopírujte veškerý obsah sl bez problémů.

Odpovězeno 09/08/2008 v 03:58
zdroj uživatelem

hlasů
5

Ano, je to možné, od .NET 3.5:

List<string> sl = new List<string>();
List<object> ol = sl.Cast<object>().ToList();
Odpovězeno 18/10/2008 v 21:26
zdroj uživatelem

hlasů
3

Mike - Věřím kontravariance není povoleno v jazyce C # a to buď

Viz obecný typ parametru rozptyl v CLR pro některé další informace.

Odpovězeno 09/08/2008 v 03:53
zdroj uživatelem

hlasů
2

Myslím, že to (kontravariance) bude skutečně podporováno v C # 4.0. http://blogs.msdn.com/charlie/archive/2008/10/27/linq-farm-covariance-and-contravariance-in-visual-studio-2010.aspx

Odpovězeno 07/11/2008 v 20:01
zdroj uživatelem

hlasů
1

Takový kovariance na generika není podporován, ale můžete vlastně dělat s poli:

object[] a = new string[] {"spam", "eggs"};

C # provádí kontroly runtime, aby vám zabránil uvedení, řekněme, o intINTO a.

Odpovězeno 09/10/2008 v 22:54
zdroj uživatelem

hlasů
1

Je to vlastně tak, že nemusíte snažit dát jakékoli liché „objekt“ ve svém „ol“ seznam varianty (jak List<object>by se zdálo, aby) - protože váš kód zřítí pak (protože seznam je skutečně List<string>a bude přijímat pouze objekty typu string ). To je důvod, proč není možné odesílat váš proměnné obecnější specifikaci.

Na Jávě je to opačně, nemáte generik a místo toho je vše Seznam objektů za běhu, a opravdu můžete nacpat jakýkoliv podivný předmět ve svém údajně-přísně psaný seznam. Výsledek hledání pro „reified generik“ vidět širší diskusi o problému java ...

Odpovězeno 10/08/2008 v 15:35
zdroj uživatelem

hlasů
0
List<string> sl = new List<string>();
List<object> ol;
ol = new List<object>(sl);
Odpovězeno 27/04/2017 v 09:52
zdroj uživatelem

hlasů
0

Mm, díky předchozí připomínky jsem našel dva způsoby, jak si to. První z nich je stále v seznamu řetězce elementů a potom odlitím do seznamu IEnumerable objektu:

IEnumerable<object> ob;
List<string> st = new List<string>();
ob = st.Cast<object>();

A druhý se vyhnout IEnumerable typ objektu, jen lití řetězec na typ objektu a potom pomocí funkce „tolist ()“ v jedné větě:

List<string> st = new List<string>();
List<object> ob = st.Cast<object>().ToList();

Líbí se mi víc druhý způsob. Doufám, že to pomůže.

Odpovězeno 17/03/2016 v 21:38
zdroj uživatelem

hlasů
0

Já mám:

private List<Leerling> Leerlingen = new List<Leerling>();

A chtěl jsem ji naplnit daty shromažďovaných v List<object> co nakonec pracoval pro mě byl tento:

Leerlingen = (List<Leerling>)_DeserialiseerLeerlingen._TeSerialiserenObjecten.Cast<Leerling>();

.Castto typ, který chcete-li získat IEnumerablez tohoto typu, typecast IEnemuerablena List<>chcete.

Odpovězeno 15/10/2009 v 10:41
zdroj uživatelem

hlasů
0

Zde je další pre-.NET 3,5 řešením pro jakékoliv IList jehož obsah lze odlévat implicitně.

public IList<B> ConvertIList<D, B>(IList<D> list) where D : B
{
    List<B> newList = new List<B>();

    foreach (D item in list)
    {
        newList.Add(item);
    }

    return newList;
}

(Na příklad Zooba Založený)

Odpovězeno 08/06/2009 v 17:34
zdroj uživatelem

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more