¿Puedo decirle a C # referencias anulables que un método es efectivamente una verificación nula en un campo

14

Considere el siguiente código:

#nullable enable
class Foo
{
    public string? Name { get; set; }
    public bool HasName => Name != null;
    public void NameToUpperCase()
    {
        if (HasName)
        {
            Name = Name.ToUpper();
        }
    }
}

En Name = Name.ToUpper () recibo una advertencia de que Name es una posible referencia nula, que es claramente incorrecta. Puedo curar esta advertencia al incluir HasName para que la condición sea if (Name! = Null).

¿Hay alguna forma de indicarle al compilador que una respuesta verdadera de HasName implica una restricción de nulabilidad en Name?

Esto es importante porque HasName en realidad podría probar muchas más cosas, y podría querer usarlo en varios lugares, o podría ser una parte pública de la superficie API. Hay muchas razones para querer incluir la verificación nula en su propio método, pero hacerlo parece romper el verificador de referencia anulable.

John Melville
fuente
1
OMI debe usar HasValueen un tipo anulable, no verificarlo null. Sin embargo, probablemente no afecte tu problema.
fredrik
Creo que para su caso, puede envolver su código #nullable disableluego #nullable enableo restorenuevamente ( docs.microsoft.com/en-us/dotnet/csharp/… ).
GaryNg
55
podrías usar el !operador "maldita sea" . if(HasName) { Name = Name!.ToUpper(); }
Jan Paolo Go
1
para una aplicación de subprocesos múltiples, puede hacer que Name sea nulo después de la comprobación de HasName, usar la variable localmente en lugar de volver a la propiedad (quién sabe qué podría hacer la propiedad en su getter) va a dar algunos errores funky (recuerde el uso de un controlador de eventos donde esto ha sucedido mucho)
XIU

Respuestas:

3

Observé los diferentes atributos System.Diagnostics.CodeAnalysisy no pude encontrar nada aplicable, lo cual es muy decepcionante. Lo más cercano que puede llegar a lo que quiere parece ser:

public bool TryGetName([NotNullWhen(true)] out string? name)
{
    name = Name;
    return name != null;
}

public void NameToUpperCase()
{
    if (TryGetName(out var name))
    {
        Name = name.ToUpper();
    }
}

Parece bastante engorroso, lo sé. Puede buscar en los documentos de MSDN atributos anulables , tal vez encuentre algo más ordenado.

V0ldek
fuente
2
Parece que necesitamos más atributos o algo así como las afirmaciones del mecanografiado
Stilgar
Elegiré esta como respuesta, porque parece que la respuesta real, como me temía, es "no, c # todavía no lo hace".
John Melville el
@JohnMelville Tampoco pude encontrar una propuesta para tal característica, así que no creo que podamos esperar que esto cambie pronto.
V0ldek
2
@XIU El compilador ya es laxo en este aspecto. Si lo hace if(Name != null) return Null.ToUpper(), no habrá advertencia para una desreferencia nula, aunque técnicamente es una condición de carrera TOCTOU. Recuerdo que Mads Torgersen habló sobre cómo consideraron eso, pero generaría tantos falsos positivos que toda la característica de tipos de referencia anulables sería efectivamente inútil: el 99% del tiempo sus propiedades no serán cambiadas por otro hilo. Entonces, todo lo que necesita hacer es hacer un atributo que haga que el cheque de esta propiedad sea tratado como un cheque nulo en otra propiedad.
V0ldek
2
Solucioné el problema de "no puedo encontrar una propuesta para este". ( github.com/dotnet/csharplang/issues/2997 ) Deséame suerte.
John Melville el
-10

La cadena es un tipo de referencia y anulable (p int?. Ej. ) Son tipos de valores anulables. Entonces realmente no puedes hacer esto string? myString; Lo que necesitas es esto:

class Foo
{
    public string Name { get; set; }
    public bool HasName => !String.IsNullOrEmpty(Name);  ////assume you want empty to be treated same way as null
    public void NameToUpperCase()
    {
        if (HasName)
        {
            Name = Name.ToUpper();
        }
    }
}
daxu
fuente