Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

217
Visualizações
Is there a difference between `x is int?` and `x is int` in C#?
class C<T> where T : struct {
    bool M1(object o) => o is T;
    bool M2(object o) => o is T?;
}

The two methods above seems to behave equally, both when passing null reference or boxed T value. However, the generated MSIL code is a bit different:

.method private hidebysig instance bool M1(object o) cil managed {
    .maxstack 8
    IL_0000: ldarg.1
    IL_0001: isinst !T
    IL_0006: ldnull
    IL_0007: cgt.un
    IL_0009: ret
}

vs

.method private hidebysig instance bool M2(object o) cil managed {
    .maxstack 8
    IL_0000: ldarg.1
    IL_0001: isinst valuetype [mscorlib]System.Nullable`1<!T>
    IL_0006: ldnull
    IL_0007: cgt.un
    IL_0009: ret
}

As you may see, the o is T? expression actually performs type check for Nullable<T> type, despite the fact that nullable types are specially handled by CLR so that C# represents boxed T? value as null reference (if T? has no value) or boxed T value. It seems impossible to get box of Nullable<T> type in pure C# or maybe even in C++/CLI (since runtime handles box opcode to support this "T? => T box / null" boxing).

Am I missing something or o is T? is practically equivalent to o is T in C#?

over 4 years ago · Santiago Trujillo
2 Respostas
Responde à pergunta

0

According to the spec (emphasis mine), in E is T, non-nullable value types of T and corresponding nullable types are handled the same way:

7.10.10 The is operator

The is operator is used to dynamically check if the run-time type of an object is compatible with a given type. The result of the operation E is T, where E is an expression and T is a type, is a boolean value indicating whether E can successfully be converted to type T by a reference conversion, a boxing conversion, or an unboxing conversion. The operation is evaluated as follows, after type arguments have been substituted for all type parameters:

  • If E is an anonymous function, a compile-time error occurs

  • If E is a method group or the null literal, of if the type of E is a reference type or a nullable type and the value of E is null, the result is false.

  • Otherwise, let D represent the dynamic type of E as follows:

    • If the type of E is a reference type, D is the run-time type of the instance reference by E.
    • If the type of E is a nullable type, D is the underlying type of that nullable type.

    • If the type of E is a non-nullable value type, D is the type of E.

  • The result of the operation depends on D and T as follows:

    • If T is a reference type, the result is true if D and T are the same type, if D is a reference type and an implicit reference conversion from D to T exists, or if D is a value type and a boxing conversion from D to T exists.
    • If T is a nullable type, the result is true if D is the underlying type of T.
    • If T is a non-nullable value type, the result is true if D and T are the same type.
    • Otherwise, the result is false.
over 4 years ago · Santiago Trujillo Relatório

0

Consider this generic method:

static bool Is<T>(object arg)
{
    return arg is T;
}

The crucial part of this method gets compiled to isinst !!T. Now you would expect Is<int?>(arg) to behave exactly the same way as arg is int?, wouldn't you? To ensure this exact consistency, the C# compiler must emit the same CIL in all the cases and let the burden of handling nullable types lie on the CLR.

The behaviour of the CLR can be viewed in the coreclr source code on GitHub: IsInst, ObjIsInstanceOf. As you can see in the second function, if the type is a nullable representation of the argument type, it returns true.

allow an object of type T to be cast to Nullable (they have the same representation)

Yes, the current behaviour of these instructions is the same, so changing is T? to is T won't make any difference (even for null argument), but to cope with any possible future changes in the CLR, the C# compiler cannot make that decision (although the probability of isinst behaviour changed is close to zero).

Nullable types are really a wondrous thing in .NET, especially due to their particular handling in the CLR, despite the fact that they have no special syntax in CIL (for compatibility). There is really no normal way of boxing a nullable type to its actual type and not the underlying one, as it would raise inconsistencies in casts and checks (is null reference equal to a boxed nullable type null or not?). However, you can trick the CLR into thinking you give it a boxed nullable type (not that you should).

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda