Atravessou esta linha de código:
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
O que significam os dois pontos de interrogação, é algum tipo de operador ternário? É difícil procurar no Google.
Atravessou esta linha de código:
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
O que significam os dois pontos de interrogação, é algum tipo de operador ternário? É difícil procurar no Google.
Respostas:
É o operador coalescente nulo e bem como o operador ternário (se-imediato). Veja também ?? Operador - MSDN .
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
expande para:
FormsAuth = formsAuth != null ? formsAuth : new FormsAuthenticationWrapper();
que se expande ainda mais para:
if(formsAuth != null)
FormsAuth = formsAuth;
else
FormsAuth = new FormsAuthenticationWrapper();
Em inglês, significa "Se o que estiver à esquerda não for nulo, use-o; caso contrário, use o que está à direita".
Observe que você pode usar qualquer número destes em sequência. A seguinte declaração irá atribuir o primeiro não-nula Answer#
para Answer
(se todas as respostas são nulos então o Answer
é null):
string Answer = Answer1 ?? Answer2 ?? Answer3 ?? Answer4;
Também vale a pena mencionar, enquanto a expansão acima é conceitualmente equivalente, o resultado de cada expressão é avaliado apenas uma vez. Isso é importante se, por exemplo, uma expressão for uma chamada de método com efeitos colaterais. (Agradecemos a @Joey por apontar isso.)
??
é deixado associativo, então a ?? b ?? c ?? d
é equivalente a ((a ?? b) ?? c ) ?? d
. "Os operadores de atribuição e o operador ternário (? :) são associativos à direita. Todos os outros operadores binários são associativos à esquerda." Fonte: msdn.microsoft.com/pt-br/library/ms173145.aspx
Só porque ninguém mais disse as palavras mágicas ainda: é o operador coalescente nulo . É definido na seção 7.12 da especificação de idioma do C # 3.0 .
É muito útil, principalmente devido ao modo como funciona quando é usado várias vezes em uma expressão. Uma expressão do formulário:
a ?? b ?? c ?? d
dará o resultado da expressão a
se for não nulo; caso contrário b
, tente c
, caso contrário, tente , caso contrário, tente d
. Curto-circuito em todos os pontos.
Além disso, se o tipo de d
for não nulo, o tipo de toda a expressão também não será nulo.
É o operador coalescente nulo.
http://msdn.microsoft.com/en-us/library/ms173224.aspx
Sim, quase impossível procurar, a menos que você saiba como é chamado! :-)
EDIT: E este é um recurso interessante de outra pergunta. Você pode encadeá-los.
Obrigado a todos, aqui está a explicação mais sucinta que encontrei no site do MSDN:
// y = x, unless x is null, in which case y = -1.
int y = x ?? -1;
-1
é apenas uma planície int
, que não é anulável).
x
é do tipo int?
, mas y
é do tipo int
, você pode escrever int y = (int)(x ?? -1)
. Ele irá analisar x
a um int
, se não é null
, ou atribuir -1
a y
se x
é null
.
Os dois pontos de interrogação (??) indicam que é um operador de coalescência.
O operador coalescente retorna o primeiro valor NON-NULL de uma cadeia. Você pode ver este vídeo do youtube que demonstra praticamente tudo.
Mas deixe-me adicionar mais ao que o vídeo diz.
Se você vir o significado em inglês de coalescer, ele diz "consolidar juntos". Por exemplo, abaixo, está um código coalescente simples que encadeia quatro cadeias.
Então, se str1
é null
que vai tentar str2
, se str2
é null
que vai tentar str3
e assim por diante até encontrar uma string com um valor não nulo.
string final = str1 ?? str2 ?? str3 ?? str4;
Em palavras simples, o operador Coalescing retorna o primeiro valor NON-NULL de uma cadeia.
É mão curta para o operador ternário.
FormsAuth = (formsAuth != null) ? formsAuth : new FormsAuthenticationWrapper();
Ou para aqueles que não fazem ensino ternário:
if (formsAuth != null)
{
FormsAuth = formsAuth;
}
else
{
FormsAuth = new FormsAuthenticationWrapper();
}
!= null
) quanto o segundo formsAuth
(após o ?
) podem ser alterados; na forma de coalescência nula, ambos assumem implicitamente os valores que você forneceu.
Se você conhece Ruby, ||=
parece C # ??
para mim. Aqui estão alguns Ruby:
irb(main):001:0> str1 = nil
=> nil
irb(main):002:0> str1 ||= "new value"
=> "new value"
irb(main):003:0> str2 = "old value"
=> "old value"
irb(main):004:0> str2 ||= "another new value"
=> "old value"
irb(main):005:0> str1
=> "new value"
irb(main):006:0> str2
=> "old value"
E em C #:
string str1 = null;
str1 = str1 ?? "new value";
string str2 = "old value";
str2 = str2 ?? "another new value";
x ||= y
desugars para algo como x = x || y
, então ??
é realmente mais parecido com o plain ||
em Ruby.
??
só se preocupa null
, enquanto que o ||
operador em Ruby, como na maioria dos idiomas, é mais sobre null
, false
ou qualquer coisa que pode ser considerado um booleano com um valor de false
(por exemplo, em algumas línguas, ""
). Isso não é uma coisa boa ou ruim, apenas uma diferença.
Nada de perigoso nisso. De fato, é lindo. Você pode adicionar um valor padrão se isso for desejável, por exemplo:
CÓDIGO
int x = x1 ?? x2 ?? x3 ?? x4 ?? 0;
int? x1 = null;
Está certo
x1
- x4
DEVE ser do tipo anulável: não faz sentido dizer, efetivamente, "o resultado é 0
se x4
for um valor que ele não pode aceitar" ( null
). "Tipo anulável" aqui inclui tipos de valores anuláveis e tipos de referência, é claro. É um erro em tempo de compilação se uma ou mais das variáveis encadeadas (exceto a última) não forem anuláveis.
Como apontado corretamente em várias respostas, que é o "operador coalescente nulo" ( ?? ), falando sobre o qual você também pode querer conferir ao primo o "Operador nulo-condicional" ( ?. Ou ? [ ) Que é um operador que muitas vezes é usado em conjunto com ??
Usado para testar nulo antes de executar uma operação de acesso de membro ( ?. ) Ou índice ( ? [ ). Esses operadores ajudam a escrever menos código para lidar com verificações nulas, especialmente para a descida nas estruturas de dados.
Por exemplo:
// if 'customers' or 'Order' property or 'Price' property is null,
// dollarAmount will be 0
// otherwise dollarAmount will be equal to 'customers.Order.Price'
int dollarAmount = customers?.Order?.Price ?? 0;
o jeito antigo sem ? e ?? de fazer isso é
int dollarAmount = customers != null
&& customers.Order!=null
&& customers.Order.Price!=null
? customers.Order.Price : 0;
o que é mais detalhado e complicado.
Apenas para sua diversão (sabendo que todos vocês são C # guys ;-).
Eu acho que se originou em Smalltalk, onde existe há muitos anos. É definido lá como:
no objeto:
? anArgument
^ self
em UndefinedObject (também conhecido como classe nil):
? anArgument
^ anArgument
Existem versões de avaliação (?) E não avaliação (??) disso.
É freqüentemente encontrado em métodos getter para variáveis privadas (instância) inicializadas preguiçosamente, que são deixadas nulas até serem realmente necessárias.
Alguns dos exemplos aqui de obtenção de valores usando coalescência são ineficientes.
O que você realmente quer é:
return _formsAuthWrapper = _formsAuthWrapper ?? new FormsAuthenticationWrapper();
ou
return _formsAuthWrapper ?? (_formsAuthWrapper = new FormsAuthenticationWrapper());
Isso impede que o objeto seja recriado toda vez. Em vez de a variável privada permanecer nula e um novo objeto ser criado em cada solicitação, isso garante que a variável privada seja atribuída se o novo objeto for criado.
??
atalho não é avaliado? new FormsAuthenticationWrapper();
é avaliado se e somente se _formsAuthWrapper
for nulo.
Eu li todo este tópico e muitos outros, mas não consigo encontrar uma resposta tão completa quanto esta.
Pelo qual eu entendi completamente o "por que usar ?? e quando usar ?? e como usar ??."
Fundação de comunicação do Windows desencadeada Por Craig McMurtry ISBN 0-672-32948-4
Há duas circunstâncias comuns em que alguém gostaria de saber se um valor foi atribuído a uma instância de um tipo de valor. A primeira é quando a instância representa um valor em um banco de dados. Nesse caso, alguém gostaria de poder examinar a instância para verificar se um valor está realmente presente no banco de dados. A outra circunstância, mais pertinente ao assunto deste livro, é quando a instância representa um item de dados recebido de alguma fonte remota. Novamente, gostaríamos de determinar a partir da instância se um valor para esse item de dados foi recebido.
O .NET Framework 2.0 incorpora uma definição de tipo genérico que fornece casos como esses nos quais se deseja atribuir nulo a uma instância de um tipo de valor e testar se o valor da instância é nulo. Essa definição de tipo genérico é System.Nullable, que restringe os argumentos de tipo genérico que podem ser substituídos por T para valorizar tipos. Instâncias de tipos construídos a partir de System.Nullable podem receber um valor nulo; de fato, seus valores são nulos por padrão. Assim, os tipos construídos a partir de System.Nullable podem ser chamados de tipos de valor anulável. System.Nullable possui uma propriedade, Value, pela qual o valor atribuído a uma instância de um tipo construído a partir dela pode ser obtido se o valor da instância não for nulo. Portanto, pode-se escrever:
System.Nullable<int> myNullableInteger = null;
myNullableInteger = 1;
if (myNullableInteger != null)
{
Console.WriteLine(myNullableInteger.Value);
}
A linguagem de programação C # fornece uma sintaxe abreviada para declarar tipos criados a partir de System.Nullable. Essa sintaxe permite abreviar:
System.Nullable<int> myNullableInteger;
para
int? myNullableInteger;
O compilador impedirá que alguém tente atribuir o valor de um tipo de valor anulável a um tipo de valor comum desta maneira:
int? myNullableInteger = null;
int myInteger = myNullableInteger;
Isso impede que se faça isso porque o tipo de valor anulável poderia ter o valor nulo, o que realmente teria nesse caso, e esse valor não pode ser atribuído a um tipo de valor comum. Embora o compilador permita esse código,
int? myNullableInteger = null;
int myInteger = myNullableInteger.Value;
A segunda instrução faria com que uma exceção fosse lançada porque qualquer tentativa de acessar a propriedade System.Nullable.Value é uma operação inválida se o tipo construído a partir de System.Nullable não recebeu um valor válido de T, o que não aconteceu neste caso.
Uma maneira adequada de atribuir o valor de um tipo de valor nulo a um tipo de valor comum é usar a propriedade System.Nullable.HasValue para verificar se um valor válido de T foi atribuído ao tipo de valor nulo:
int? myNullableInteger = null;
if (myNullableInteger.HasValue)
{
int myInteger = myNullableInteger.Value;
}
Outra opção é usar esta sintaxe:
int? myNullableInteger = null;
int myInteger = myNullableInteger ?? -1;
Pelo qual o número inteiro ordinário myInteger é atribuído ao valor do número inteiro anulável "myNullableInteger" se este último recebeu um valor inteiro válido; caso contrário, myInteger recebe o valor de -1.
É um operador coalescente nulo que funciona de maneira semelhante a um operador ternário.
a ?? b => a !=null ? a : b
Outro ponto interessante para isso é: "Um tipo anulável pode conter um valor ou pode ser indefinido" . Portanto, se você tentar atribuir um tipo de valor nulo a um tipo de valor nulo, você receberá um erro em tempo de compilação.
int? x = null; // x is nullable value type
int z = 0; // z is non-nullable value type
z = x; // compile error will be there.
Então, para fazer isso usando? operador:
z = x ?? 1; // with ?? operator there are no issues
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
é equivalente a
FormsAuth = formsAuth != null ? formsAuth : new FormsAuthenticationWrapper();
Mas o mais legal é que você pode prendê-los, como outras pessoas disseram. O que você não mencionou é que você pode realmente usá-lo para lançar uma exceção.
A = A ?? B ?? throw new Exception("A and B are both NULL");
O ??
operador é chamado de operador de coalescência nula. Retorna o operando esquerdo se o operando não for nulo; caso contrário, ele retornará o operando do lado direito.
int? variable1 = null;
int variable2 = variable1 ?? 100;
Defina variable2
como o valor de variable1
, se variable1
NÃO for nulo; caso contrário, se for variable1 == null
definido variable2
como 100.
Outros descreveram Null Coalescing Operator
muito bem. Para os interessados, há uma sintaxe abreviada em que esta (a questão SO):
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
é equivalente a isso:
FormsAuth ??= new FormsAuthenticationWrapper();
Alguns acham mais legível e sucinto.