[C#]Cast vid list generics och if-else

Permalänk

[C#]Cast vid list generics och if-else

Sprang över två intressanta saker i .NET 2.0 idag som säkert nån kan ha nytta/vara intresserad av:

1. Cast vid list generics

string s = "A"; object o = s;

Detta är inget konstigt, string är ett objekt.

Men om man har följande:

List<string> strings = new List<string>(); strings.Add("A"); List<object> objects = strings;

så kommer det att resultera i ett kompileringsfel:

Cannot implicitly convert type 'System.Collections.Generic.List<string>' to 'System.Collections.Generic.List<object>'

Ok, så då testar vi:

List<string> strings = new List<string>(); strings.Add("A"); List<object> objects = (List<object>)strings;

Men aningen förvånande så resulterar detta i:

Error 1 Cannot convert type 'System.Collections.Generic.List<string>' to 'System.Collections.Generic.List<object>'

Orsaken är att List<T> inte håller fast vid T's (typens) ärvningsstruktur (inheritance tree).

Detta är lite irriterande i vissa situationer och jag har inte kommit på något bättre sätt än att iterera genom listan och casta varje element skillt:

List<object> objects = new List<object>(strings.Count); foreach (string s in strings) { objects.Add((object)s); }

Eller lite snyggare:

List<object> objects = strings.ConvertAll<object>( delegate(string s) { return (object)s; });

2. Cast vid If-else

Vi har ett helt vanligt objekt:

public class Customer { private DateTime m_LastOrderDate; public Customer(){} public DateTime LastOrderDate { get { return m_LastOrderDate; } internal set { m_LastOrderDate = value; } } }

Sedan har vi ett dataobjekt som vill visa ett attribut på en instans av Customer och om vi inte har någon Customer så ska ingenting visas, dvs. vi använder oss av en nullable DateTime:

public DateTime? LastOrderDate { get { return m_Customer != null ? m_Customer.LastOrderDate : null; } }

Detta kommer att resultera i ett kompileringsfel:

Error 1 Type of conditional expression cannot be determined because there is no implicit conversion between 'System.DateTime' and '<null>'

Vilket ju är lite märkligt, eftersom DateTime är en delmängd av nullable DateTime! Följande (exakt samma sak, bara annan notation!) gårdock fint:

public DateTime? LastOrderDate { get { if (m_Customer != null) return m_Customer.LastOrderDate; return null; } }

Helt otroligt.

Vad man måste göra är att explicit casta vår DateTime till en nullable DateTime:

public DateTime? LastOrderDate { get { return m_Customer != null ? (DateTime?)m_Customer.LastOrderDate : null; } }

Visa signatur

"Mies saa kaatua mutta ei karata." -- Adolf Ehrnrooth IR 7, Äyräpää 1944.

Permalänk

Det har väl inte undgått dig att C# är ett _statiskt typat_ språk?

Permalänk
Citat:

Ursprungligen inskrivet av BobbyFromDallas
Det har väl inte undgått dig att C# är ett _statiskt typat_ språk?

Nee, det vet jag nog, precis som C++ och Java. I punkt 1 kan jag acceptera att detta inte går, men i punkt 2 förstår jag inte varför kompilatorn klagar. En DateTime är en DateTime? och då dessutom följande går igenom:

public DateTime? LastOrderDate { get { if (m_Customer != null) return m_Customer.LastOrderDate; return null; } }

Vi returnerar en DateTime i en property som förvänatr sig en DateTime?, så vad skiljer detta från:

public DateTime? LastOrderDate { get { return m_Customer != null ? m_Customer.LastOrderDate : null; } }

Visa signatur

"Mies saa kaatua mutta ei karata." -- Adolf Ehrnrooth IR 7, Äyräpää 1944.

Permalänk
Avstängd

Intressant fenomen du hittat. Har du hittat ngn information om vad som skiljer jämförelseoperatorn och en if sats?

Tycker att reg exp i kompilatorn borde vara likadant, ngt i stil med

Jämförelseoperatorn: (bool ) ? exp : exp;
if sats: if(bool) exp;

Skumt...

Permalänk
Medlem

Ta en titt på http://www.thescripts.com/forum/thread279569.html för en diskussion om villkorsoperatorn och dess omvandlingar.

Förövrigt går

public DateTime? LastOrderDate { get { return customer != null ? customer.LastOrderDate : null; } }

igenom om man gör propertyn nollbar och använder .GetValueOrDefault

// class Customer public DateTime? LastOrderDate { get { return lastOrderDate; } internal set { lastOrderDate = value.GetValueOrDefault(); } }

EDIT: Angående punkt ett så kanske någonting sånt här gör det kortare.

List<string> strings = new List<string> ( ); strings.Add ( "A" ); strings.Add ( "B" ); strings.Add ( "C" ); List<object> objects = new List<object> ( strings.ToArray ( ) );

Permalänk
Medlem

Re: [C#]Cast vid list generics och if-else

Citat:

Ursprungligen inskrivet av Turbo_tail
Sprang över två intressanta saker i .NET 2.0 idag som säkert nån kan ha nytta/vara intresserad av:

1. Cast vid list generics

(...)

List<string> strings = new List<string>(); strings.Add("A"); List<object> objects = strings;

så kommer det att resultera i ett kompileringsfel:

Cannot implicitly convert type 'System.Collections.Generic.List<string>' to 'System.Collections.Generic.List<object>'

Har råkat ut för samma grej nu, har en klass med en medlemsvariabel List<Derived> och skulle vilja returnera den från en funktion som List<Base>. Nu tror jag iofs att jag kan komma runt det genom att lösa det på ett annat sätt som inte alls kräver att man kan komma åt listan utifrån.

Men, vad jag tänkte fråga (för jag antar att det inte finns nån lösning på problemet?) är en lite abstrakt fråga kanske.. men, skulle ni säga att om man behöver göra en sån här grej, så betyder det att man har designat fel?

Kanske är en rätt svår fråga, men t.ex. så vill man ju, för att ta ett exempel på nåt som ofta beror på feldesign, inte göra såna här grejer:

foreach( Base b in m_BaseList ) { if (b.Type == "Derived1" ) { gör nåt..} if (b.Type == "Derived2" ) { gör nåt annat..} if (b.Type == "Derived2" ) { gör nåt tredje..} }

Det är ju lite åt samma håll.

Åh, nu insåg jag precis varför man inte får göra så (iaf en anledning). Det är nog t.o.m. en item i Effective C++ tror jag.

För då skulle man kunna göra

List<Derived> kaka = hej.GetList(); List<Base> apa = kaka; apa.Add(new Derived2() );

Och det är ju rätt självklart att det inte skulle vara så hett.

Visa signatur

Min hemsida: http://www.srekel.net
Pocket Task Force: http://ptf.srekel.net
Kaka e gott! http://kaka.srekel.net