2008-11-14 14 views
77

¿Existe un atributo simple o contrato de datos que pueda asignar a un parámetro de función que impida que se pase null en C# /. NET? Idealmente, esto también se verificaría en tiempo de compilación para asegurarse de que el literal null no se esté utilizando en ningún lugar para ello y en tiempo de ejecución arroje ArgumentNullException.Marcar los parámetros como NOT anulables en C# /. NET?

Actualmente escribo algo así como ...

if (null == arg) 
    throw new ArgumentNullException("arg"); 

... para todos los argumentos que espero que no sea null.

En la misma nota, ¿existe un opuesto a Nullable<> por lo que el siguiente sería un fracaso:

NonNullable<string> s = null; // throw some kind of exception 

Respuesta

61

No hay nada disponible en tiempo de compilación, por desgracia.

Tengo un poco de hacky solution que publiqué recientemente en mi blog, que usa una nueva estructura y conversiones.

En .NET 4.0 con el material Code Contracts, la vida será mucho mejor. Todavía sería muy agradable tener una sintaxis de lenguaje real y soporte en torno a la no anulabilidad, pero los contratos de código ayudarán mucho.

También tengo un método de extensión en MiscUtil llamado ThrowIfNull que lo hace un poco más simple.

Un último punto: cualquier razón para usar "if (null == arg)" en lugar de "if (arg == null)"? Encuentro este último más fácil de leer, y el problema que el primero resuelve en C no se aplica a C#.

+1

> Desafortunadamente, no hay nada disponible en tiempo de compilación. > ... > Sería bastante agradable tener una sintaxis del lenguaje real y soporte en no anulabilidad Estoy de acuerdo. También me gustaría ver que se produzcan errores en tiempo de compilación. – AndrewJacksonZA

+2

@Jon, ¿no funciona "if (arg = null)" si hay un molde implícito a bool definido? Admito que puede parecer perverso, pero compila ... –

+10

@ ThomasS.Trias: Sí, en ese caso marginal increíblemente oscuro, * combinado * con un error tipográfico, combinado con la falta de pruebas en torno a ese código, tú " d termina con un problema. En ese momento, creo que tienes problemas mayores :) –

8

Verifique los validadores en la biblioteca de la empresa. Usted puede hacer algo como:

private MyType _someVariable = TenantType.None; 
[NotNullValidator(MessageTemplate = "Some Variable can not be empty")] 
public MyType SomeVariable { 
    get { 
     return _someVariable; 
    } 
    set { 
     _someVariable = value; 
    } 
} 

Luego, en el código cuando se desea validarlo:

Microsoft.Practices.EnterpriseLibrary.Validation.Validator myValidator = ValidationFactory.CreateValidator<MyClass>(); 

ValidationResults vrInfo = InternalValidator.Validate(myObject); 
-7
public void foo(int? id, string name) 
{ 
    if (id == null) 
    { 
     throw new ArgumentNullException("id"); 
    } 
    if (name == null) 
    { 
     throw new ArgumentNullException("name"); 
    } 

    this.foo = id.Value; 
    this.fooName = name; 
} 

Hay que ir, de lo contrario sólo definen otra declaración.

+6

Downvoted. 1. Lea el código en cuestión bajo el encabezado "Actualmente escribo algo como ...". 2. Para el int? tipo. –

0

no el más bonito, pero:

public static bool ContainsNullParameters(object[] methodParams) 
{ 
    return (from o in methodParams where o == null).Count() > 0; 
} 

que podría ser más creativos en el método ContainsNullParameters también:

public static bool ContainsNullParameters(Dictionary<string, object> methodParams, out ArgumentNullException containsNullParameters) 
     { 
      var nullParams = from o in methodParams 
          where o.Value == null 
          select o; 

      bool paramsNull = nullParams.Count() > 0; 


      if (paramsNull) 
      { 
       StringBuilder sb = new StringBuilder(); 
       foreach (var param in nullParams) 
        sb.Append(param.Key + " is null. "); 

       containsNullParameters = new ArgumentNullException(sb.ToString()); 
      } 
      else 
       containsNullParameters = null; 

      return paramsNull; 
     } 

, por supuesto, usted podría utilizar un interceptor o la reflexión pero estos son fáciles de seguir/utilizar con poca sobrecarga

+3

Muy mala práctica al usar tales consultas: 'return (desde o en el métodoParams donde o == nulo) .Count()> 0;' Uso: 'return methodParams.Any (o => o == null); ' será mucho más rápido en colecciones grandes – Yavanosta

+0

¿Por qué se desvía la excepción? ¿Por qué no solo tirarlo? –

-2

Ok, esta respuesta es un poco tarde, pero así es como lo estoy resolviendo:

public static string Default(this string x) 
{ 
    return x ?? ""; 
} 

Utilice este método de exension, entonces puede tratar la secuencia vacía y nula como la misma cosa.

E.g.

if (model.Day.Default() == "") 
{ 
    //.. Do something to handle no Day .. 
} 

No es ideal Sé que debe recordar llamar al valor predeterminado en todas partes, pero es una solución.

+4

¿cómo es esto mejor/más fácil que las verificaciones (x == nulo)? o la función String.IsNotNullOrEmpty. – Batavia

+0

No es mucho mejor que 'string.IsNotNullOrEmpty' realmente distinto del azúcar de tener lo que te importa a la izquierda. Se puede alimentar a otras funciones (longitud, concatenación) etc. Marginalmente mejor. –

12

Sé que esto es una pregunta muy antigua, pero éste había desaparecido aquí:

Si utiliza ReSharper puede usar la Annotated Framework.

+1

Curiosamente, su aplicación compilada no tendrá referencia de JetBrains.Annotations.dll por lo que no tiene que distribuirla con la aplicación: [Cómo usar las anotaciones de JetBrains para mejorar las inspecciones de ReSharper] (http: // blog .jetbrains.com/dotnet/2015/08/12/cómo-usar-jetbrains-annotations-to-improve-resharper-inspections /) – Lu55

2

Sé que es muy tarde para esta pregunta, pero creo que la respuesta será relevante a medida que la última versión importante de C# se acerque a su lanzamiento, y luego se lance. En C# 8.0 se producirá un cambio importante, C# asumirá todos los tipos se consideran no nulos.

Según Mads Torgersen:

El problema es que referencias nulas son tan útiles. En C#, son el valor predeterminado de cada tipo de referencia. ¿Qué otra cosa sería el valor predeterminado? ¿Qué otro valor tendría una variable, hasta que pueda decidir qué más asignarle? ¿Con qué otro valor podríamos alisar una serie de referencias recientemente asignadas , hasta que llegue al completándolas?

Además, a veces nulo es un valor razonable en sí mismo. A veces, desea representar el hecho de que, por ejemplo, un campo no tiene un valor . Que está bien pasar "nada" por un parámetro. El énfasis es en algunas ocasiones, sin embargo. Y aquí está otra parte del problema: Los lenguajes como C# no le permiten expresar si un nulo aquí es una buena idea o no.

lo que la resolución se indica por Mads, es decir:

  1. Creemos que es más común querer una referencia de no ser nulo. Los tipos de referencia anulables serían del tipo más raro (aunque no tenemos buenos datos para decirnos por cuánto), por lo que son los que deberían requerir una nueva anotación.

  2. El lenguaje ya tiene una noción de - y una sintaxis para - tipos de valores que aceptan nulos. La analogía entre los dos haría que el lenguaje además sea conceptualmente más fácil y lingüísticamente más simple.

  3. Parece correcto que usted no debe agobiarse ni a usted ni a su consumidor con engorrosos valores nulos a menos que haya decidido activamente que los quiere. Los nulos, no la ausencia de ellos, deberían ser lo que explícitamente tiene que habilitar.

Un ejemplo de la función deseada:

public class Person 
{ 
    public string Name { get; set; } // Not Null 
    public string? Address { get; set; } // May be Null 
} 

La vista previa está disponible para Visual Studio 2017, 15.5.4+ vista previa.

Cuestiones relacionadas