Pergunta

Falha:

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

Êxito:

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

O erro na primeira instrução é:

Tipo de expressão condicional não pode ser determinado porque não há nenhuma conversão implícita entre 'int' e 'cadeia'.

Por que há a necessidade de ser, porém, eu estou atribuindo a elas valores para uma variável do tipo object.

Editar: O exemplo acima é trivial, sim, mas há exemplos em que isso seria muito útil:

int? subscriptionID; // comes in as a parameter

EntityParameter p1 = new EntityParameter("SubscriptionID", DbType.Int32)
{
    Value = ((subscriptionID == null) ? DBNull.Value : subscriptionID),
}
Foi útil?

Solução

usar:

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

A questão é que o tipo de retorno do operador condicional não pode ser determinado sem ambiguidade. Ou seja, entre int e string, não há melhor escolha. O compilador sempre usará o tipo de expressão verdadeira e lançará implicitamente a expressão falsa, se necessário.

Editar:Em seu segundo exemplo:

int? subscriptionID; // comes in as a parameter

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

PS:
Isso não é chamado de 'operador ternário'. Isto é um operador ternário, mas é chamado de 'operador condicional'.

Outras dicas

Embora as outras respostas são correto, no sentido de que eles fazem verdadeiras e relevantes declarações, existem algumas sutis pontos da linguagem de design aqui que ainda não foi expressa ainda.Diversos fatores contribuem para o design atual do operador condicional.

Primeiro, é desejável como muitas expressões como possível ter uma inequívoca tipo que pode ser determinado unicamente a partir do conteúdo da expressão.Isso é desejável por várias razões.Por exemplo:ele faz a construção de um motor de IntelliSense muito mais fácil.Você digita x.M(some-expression. e o IntelliSense precisa ser capaz de analisar alguns expressão, determinar o seu tipo, e produzir uma lista suspensa ANTES de IntelliSense sabe qual o método x.M se refere.IntelliSense não sabe o que x.M refere-se a certeza se M é sobrecarregado até que ele vê todos os argumentos, mas você ainda não digitou no mesmo o primeiro argumento ainda.

Segundo, nós preferimos informações de tipo de fluxo "de dentro para fora", devido, precisamente, o cenário que acabei de mencionar:resolução de sobrecarga.Considere o seguinte:

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

O que se deve fazer?Ele deve chamar o objeto de sobrecarga?Deve ele, às vezes, chamada de seqüência de caracteres de sobrecarga e, por vezes, chamada int sobrecarga?O que se você tivesse outra sobrecarga, dizer M(IComparable x) -- quando você pegá-lo?

As coisas ficam muito complicadas quando informações de tipo de "fluxos de ambos os lados".Dizendo: "eu estou atribuindo isso a uma variável do tipo object, portanto, o compilador deve saber que é OK para escolher o objeto do tipo" não lavar;é frequentemente o caso que nós não sabemos o tipo de variável que você está atribuindo porque é isso que nós estamos no processo de tentar descobrir.Resolução de sobrecarga é exatamente o processo de trabalho os tipos de parâmetros, que são as variáveis que você está atribuindo os argumentos, a partir dos tipos dos argumentos.Se os tipos dos argumentos depende do tipo para o qual estão sendo atribuído, em seguida, temos uma circularidade em nosso raciocínio.

O tipo de informação que "o fluxo de ambos os lados" para expressões lambda;implementação eficiente que me levou a maior parte do ano.Eu escrevi uma longa série de artigos que descrevem algumas das dificuldades na concepção e implementação de um compilador que pode fazer análise, onde o tipo de fluxos de informação complexos, expressões com base no contexto em que a expressão é, possivelmente, a ser utilizado;a parte um é aqui:

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

Você pode dizer "bem, OK, não vejo por que o fato de que eu sou a atribuir ao objecto não pode ser utilizado com segurança pelo compilador, e não vejo por que é necessário para que a expressão tem uma inequívoca do tipo, mas porque não é o tipo de expressão de objeto, uma vez que ambos int e string são convertíveis em objeto?" Isso me leva ao terceiro ponto:

Terceiro, uma das sutil, mas aplicada de forma consistente os princípios de design de C# é "não produzem tipos de magia".Quando é fornecida uma lista de expressões a partir do qual devemos determinar um tipo, o tipo de determinarmos está sempre na lista em algum lugar.Nós nunca magia de um novo tipo e escolha-o para você;o tipo que você recebe é sempre aquele que você nos deu para escolher.Se você disser para encontrar o melhor tipo em um conjunto de tipos, encontramos o melhor tipo EM que o conjunto de tipos.No conjunto {int, string}, não existe um melhor tipo comum, a forma não é, digamos, "Animal, Animal, Mamífero, Wallaby".Essa decisão de projeto aplica-se o operador condicional, para a inferência de tipo unificação cenários, a inferência de tipo implícito tipos de matriz, e assim por diante.

A razão para esta decisão de projeto é que ele torna mais fácil para o comum dos seres humanos, para descobrir o que o compilador vai fazer em qualquer situação onde uma melhor tipo deve ser determinada;se você sabe que um tipo que está ali, olhando na cara, vai ser escolhido, é muito mais fácil descobrir o que vai acontecer.

Ele também evita ter de trabalhar muito de regras complexas sobre qual é o melhor tipo comum de um conjunto de tipos quando há conflitos.Suponha que você tenha os tipos de {Foo Bar}, onde ambas as classes implementam IBlah, e ambas as classes herdam de Baz.Qual é o melhor tipo comum, IBlah, que tanto a implementar, ou Baz, que tanto se estender?Não queremos ter que responder a esta pergunta;queremos evitá-lo inteiramente.

Finalmente, observe que o compilador C# realmente é a determinação dos tipos de sutilmente errado, em alguns casos obscuros.Meu primeiro artigo sobre o que é aqui:

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

É possível argumentar que, na verdade, o compilador faz isso direito e a especificação é errado;o design de implementação na minha opinião é melhor do que o do spec'd design.

Enfim, isso é apenas algumas das razões para o design desse aspecto particular do operador ternário.Há outras sutilezas aqui, por exemplo, como o verificador CLR determina se um dado conjunto de ramificação de caminhos são garantidos para deixar o tipo correto na pilha em todos os caminhos possíveis.Discutir em detalhe me levaria ao invés de longe.

Qual é o recurso X desta forma, muitas vezes é uma pergunta muito difícil de responder.É muito mais fácil para responder o comportamento real.

Meu palpite para a razão.O operador condicional é permitido de forma sucinta e laconicamente usar uma expressão booleana para escolher entre 2 valores relacionados.Eles devem ser relacionados como eles estão sendo usados em um único local.Se o usuário vez pega 2 alheios valores talvez o tinha um sutil erro / bug lá de código e compilador é melhor alertando-os para este, ao invés de incluir implicitamente carcaça para o objeto.O que pode ser algo que não esperava.

"int" é um tipo primitivo, não um objeto enquanto "string" é considerada mais um "objeto primitivo". Quando você faz algo como "Objeto O = 1", você está realmente boxe o "int" para um "int32". Aqui está um link para um artigo sobre boxe:

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

Geralmente, o boxe deve ser evitado devido ao desempenho perdas difíceis de rastrear.

Quando você usa uma expressão ternária, o compilador não analisa a variável de atribuição para determinar qual é o tipo final. Para dividir sua declaração original sobre o que o compilador está fazendo:

Declaração: objeto o = ((1 == 2)? 1: "teste");

Compilador:

  1. Quais são os tipos de "1" e "teste" em '((1 == 2)? 1: "teste")? Eles combinam?
  2. O tipo final do número 1 corresponde ao tipo de operador de atribuição para 'Objeto O'?

Como o compilador não avalia o #2 até que o #1 seja concluído, ele falha.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top