Domanda

Non riesce:

object o = ((1==2) ? 1 : "test");

Riesce:

object o;
if (1 == 2)
{
    o = 1;
}
else
{
    o = "test";
}

L'errore nella prima istruzione è:

Tipo di espressione condizionale non può essere determinato perché non c'è conversione implicita tra 'int' e 'string'.

Perché ci devono essere, però, mi sento di assegnare tali valori ad una variabile di tipo oggetto.

Edit: L'esempio sopra è banale, sì, ma ci sono esempi in cui questo sarebbe molto utile:

int? subscriptionID; // comes in as a parameter

EntityParameter p1 = new EntityParameter("SubscriptionID", DbType.Int32)
{
    Value = ((subscriptionID == null) ? DBNull.Value : subscriptionID),
}
È stato utile?

Soluzione

utilizzo:

object o = ((1==2) ? (object)1 : "test");

Il problema è che il tipo di ritorno del operatore condizionale non può essere un-ambiguo determinata. Vale a dire, tra int e la stringa, non c'è scelta migliore. Il compilatore utilizzerà sempre il tipo della vera espressione, e gettato implicitamente la falsa espressione, se necessario.

Modifica In te secondo esempio:

int? subscriptionID; // comes in as a parameter

EntityParameter p1 = new EntityParameter("SubscriptionID", DbType.Int32)
{
    Value = subscriptionID.HasValue ? (object)subscriptionID : DBNull.Value,
}

PS:
Questo non si chiama 'operatore ternario.' E ' è un operatore ternario, ma è chiamata la 'operatore condizionale.'

Altri suggerimenti

Anche se le altre risposte corretto, nel senso che fanno vera e dichiarazioni rilevanti, ci sono alcune sottili punti di linguaggio di design qui che non sono state espresse ancora.Diversi fattori contribuiscono al disegno corrente dell'operatore condizionale.

Primo, è auspicabile che, come molte espressioni possibile avere una chiara tipo che può essere determinata esclusivamente dal contenuto dell'espressione.Questo è utile per diversi motivi.Per esempio:esso rende la costruzione di un IntelliSense motore molto più facile.Si tipo x.M(some-expression. e IntelliSense deve essere in grado di analizzare alcuni di espressione, determinare il tipo e produrre un elenco a discesa PRIMA di IntelliSense sa che cosa è il metodo x.M si riferisce.IntelliSense non può sapere cosa x.M si riferisce di sicuro se M è sovraccarico fino a quando si vede tutti gli argomenti, ma non è stato digitato anche il primo argomento di sicurezza.

Secondo, noi preferiamo informazioni di tipo a flusso "dall'interno verso l'esterno", a causa proprio di scenario che ho appena citato:la risoluzione dell'overload.Si consideri il seguente:

void M(object x) {}
void M(int x) {}
void M(string x) {}
...
M(b ? 1 : "hello");

Che cosa dovrebbe fare?Dovrebbe chiamare l'oggetto di sovraccarico?Dovrebbe a volte chiamata la stringa di sovraccarico e a volte chiamata int sovraccarico?Se tu non avessi altro da sovraccarico, dire M(IComparable x) -- quando la prendete?

Le cose si fanno molto complicate quando il tipo di informazioni che scorre in entrambi i modi".Dicendo "io sono l'assegnazione di questa cosa a una variabile di tipo object, quindi il compilatore deve sapere che è OK per scegliere un oggetto come il tipo" non lavare;e ' spesso il caso che non sappiamo il tipo di variabile che si sta assegnando, perché è di questo che stiamo nel processo di cercare di capire.La risoluzione dell'Overload è esattamente il processo di elaborazione dell'tipi di parametri, che sono le variabili a cui assegnare le argomentazioni, dal tipo di argomenti.Se i tipi di argomenti dipendono dai tipi a cui sono stati assegnati, quindi abbiamo una circolarità nel nostro ragionamento.

Il tipo di informazioni "flusso in entrambi i modi" per le espressioni lambda;l'attuazione efficiente mi ha preso la parte migliore di un anno.Ho scritto una lunga serie di articoli che descrivono alcune delle difficoltà nella progettazione e implementazione di un compilatore in grado di fare analisi in cui il tipo di flussi di informazioni in complesso di espressioni in base al contesto in cui l'espressione è, eventualmente, di essere utilizzato;la prima parte è qui:

http://blogs.msdn.com/ericlippert/archive/2007/01/10/lambda-expressions-vs-anonymous-methods-part-one.aspx

Si potrebbe dire "beh, OK, non vedo perché il fatto che io sono l'assegnazione di un oggetto non può essere utilizzato in modo sicuro dal compilatore, e non vedo il motivo per cui è necessario per l'espressione di un chiaro tipo, ma perché non è il tipo di oggetto di espressione, dal momento che entrambi int e string sono convertibili in oggetto?" Questo mi porta al terzo punto:

Terzo, uno dei sottili ma sempre applicato i principi di progettazione di C#, è: "non produrre i tipi di magia".Quando è dato un elenco di espressioni di cui si deve determinare un tipo di il tipo si determina è sempre in lista da qualche parte.Non abbiamo mai la magia di un nuovo tipo e scegliere per voi;il tipo che si ottiene è sempre uno che ci ha dato da scegliere.Se dici a trovare la migliore digitare un insieme di tipi, troviamo il miglior tipo di set di tipi.Nell'insieme {int, string}, non c'è più tipo comune, il modo c'è, come dire, "di Animali, Tartarughe, Mammiferi, Wallaby".Questa decisione si applica per l'operatore condizionale, per inferenza del tipo di unificazione scenari, la deduzione di tipizzata in modo implicito tipi di matrice, e così via.

Il motivo di questa decisione è che rende più facile per la gente comune per capire che il compilatore sta andando a fare in una determinata situazione in cui un tipo migliore deve essere determinato;se sai che un tipo che è proprio lì, a fissare in faccia, sta per essere scelto, allora è molto più facile capire cosa sta per accadere.

Evita anche noi di dover lavorare fuori un sacco di regole complesse e su qual è il miglior tipo comune di un insieme di tipi quando ci sono conflitti.Si supponga di avere tipi {Foo, Bar}, in cui entrambe le classi implementano IBlah, e entrambe le classi ereditano da Baz.Quale è il miglior tipo comune, IBlah, che sia ad implementare, o Baz, che si estendono?Non vogliamo rispondere a questa domanda;vogliamo evitare del tutto.

Infine, faccio notare che il compilatore C# viene effettivamente la determinazione dei tipi sottilmente sbagliato, in qualche oscuro casi.Il mio primo articolo su quello che c'è qui:

http://blogs.msdn.com/ericlippert/archive/2006/05/24/type-inference-woes-part-one.aspx

Si potrebbe sostenere che in realtà il compilatore non è di destra e la specifica è sbagliato;l'attuazione di design è a mio parere meglio la spec piacerebbe design.

Comunque, questo è solo alcune delle ragioni per la progettazione di questo particolare aspetto dell'operatore ternario.Ci sono altre sottigliezze qui, per esempio, come il CLR verificatore determina se un dato insieme di bivi sono garantiti per lasciare il corretto tipo di pila in tutti i possibili percorsi.Discutere in dettaglio mi avrebbero piuttosto lontano.

Perché la caratteristica X in questo modo è spesso una domanda molto difficile a cui rispondere. E 'molto più facile rispondere il comportamento effettivo.

La mia ipotesi istruita sul perché. L'operatore condizionale è consentito succintamente e conciso utilizzare un'espressione booleana per scegliere tra 2 valori relativi. Essi devono essere correlati in quanto vengono utilizzati in un unico luogo. Se l'utente sceglie invece 2 valori non imparentati forse aveva una sottile battitura / errore nel codice lì e il compilatore è meglio avvertendoli questo piuttosto che implicitamente colata di opporsi. Quale può essere qualcosa che non si aspettavano.

"int" è un tipo primitivo, non un oggetto mentre "stringa" è considerato più di un "oggetto primitivo". Quando fai qualcosa come "oggetto o = 1", si sta effettivamente boxe il "int" ad un "Int32". Ecco un link ad un articolo di boxe:

http://msdn.microsoft.com/en-us/magazine /cc301569.aspx

In generale, la boxe dovrebbe essere evitato a causa di prestazioni perde che sono difficili da rintracciare.

Quando si utilizza un'espressione ternaria, il compilatore non guarda la variabile assegnazione a tutti per determinare il tipo di finale. Per abbattere il vostro dichiarazione originale in quello che il compilatore sta facendo:

Dichiarazione: oggetto o = ((1 == 2) 1: "test");

Compiler:

  1. Quali sono i tipi di "1" e "test" in '((1 == 2) 1:? "Test")'? Non corrispondono?
  2. Fa il tipo di finale dal # 1 corrisponde al tipo di operatore di assegnazione per 'oggetto o'?

Dato che il compilatore non valuta 2 # 1 # fino a quando è fatto, non riesce.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top