2008-11-14 8 views
77

Gibt es ein einfaches Attribut oder einen Datenvertrag, den ich einem Funktionsparameter zuweisen kann, der verhindert, dass null in C# /. NET übergeben wird? Idealerweise würde dies auch zur Kompilierzeit prüfen, um sicherzustellen, dass das Literal null nirgendwo dafür verwendet wird und zur Laufzeit ArgumentNullException geworfen wird.Markiere Parameter als NULL in C# /. NET NULL?

Zur Zeit schreibe ich so etwas wie ...

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

... für jedes Argument, das ich null nicht erwarten sein.

Auf die gleiche Note, gibt es ein gegenüber Nullable<> wobei folgende scheitern würde:

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

Antwort

61

Es zur Compile-Zeit verfügbar ist nichts, leider.

Ich habe ein bisschen von hacky solution, die ich in meinem Blog vor kurzem veröffentlicht, die eine neue Struktur und Konvertierungen verwendet.

In .NET 4.0 mit den Code Contracts Sachen wird das Leben viel schöner. Es wäre immer noch ziemlich nett, die aktuelle Sprachsyntax zu haben und die Nicht-NULL-Fähigkeit zu unterstützen, aber die Code-Verträge werden viel helfen.

Ich habe auch eine Erweiterungsmethode in MiscUtil namens ThrowIfNull, die es ein bisschen einfacher macht.

Ein letzter Punkt - ein Grund für die Verwendung von "if (null == arg)" anstelle von "if (arg == null)"? Ich finde das Letztere leichter zu lesen, und das Problem, das der frühere in C löst, trifft nicht auf C# zu.

+1

> Zur Kompilierzeit ist leider nichts verfügbar. > ... > Es wäre immer noch ziemlich nett, die aktuelle Sprachsyntax und Unterstützung rund um die NULL-Zulässigkeit zu haben Ich stimme zu. Ich möchte auch, dass Kompilierungsfehler auftreten. – AndrewJacksonZA

+2

@Jon, funktioniert nicht "if (arg = null)" funktioniert, wenn es eine implizite Umwandlung zu bool defined gibt? Ich gebe zu, es scheint pervers, aber es kompiliert ... –

+10

@ ThomasS.Trias: Ja, in diesem unglaublich obskuren Rand Fall, * kombiniert * mit einem Tippfehler, kombiniert mit einem Mangel an Tests um diesen Code, Sie ' d am Ende mit einem Problem. Zu diesem Zeitpunkt denke ich, dass Sie größere Probleme haben :) –

8

Überprüfen Sie die Validierer in der Enterprise-Bibliothek. Sie können so etwas wie tun:

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

dann in Ihrem Code, wenn Sie es überprüfen möchten:

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; 
} 

Dort gehen Sie, sonst nur andere Anweisung definieren.

+6

Downvoted. 1. Lesen Sie den entsprechenden Code unter der Überschrift "Aktuell schreibe ich etwas wie ...". 2. Für den Int? Art. –

0

nicht die schönste, aber:

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

Sie könnten mehr kreativ in der ContainsNullParameters Methode erhalten:

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; 
     } 

natürlich Sie einen Abfangjäger oder Reflexion nutzen könnten, aber diese sind leicht zu folgen/Verwenden Sie mit wenig Overhead

+3

Sehr schlechte Praxis mit solchen Abfragen: 'return (von o in methodParams wo o == null) .Count()> 0;' Verwenden: 'return methodParams.Any (o => o == null); ' es wird bei großen Sammlungen viel schneller sein – Yavanosta

+0

Warum die Ausnahme ausgeben? Warum nicht einfach werfen? –

-2

Ok, diese Antwort ist ein bisschen spät, aber hier ist, wie ich es lösen:

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

Verwenden Sie diese Erweiterungsmethode, dann können Sie null und leere Zeichenfolge als die gleiche Sache behandeln.

z.

Nicht ideal Ich weiß, wie Sie daran denken müssen, Standard überall anrufen, aber es ist eine Lösung.

+4

Wie ist das besser/einfacher als die (x == null) Kontrollen? oder die String.IsNotNullOrEmpty-Funktion. – Batavia

+0

Nicht viel besser als "string.IsNotNullOrEmpty" wirklich anders als der Zucker der Sache, die Sie auf der linken Seite kümmern. Kann in andere Funktionen (Länge, Verkettung) usw. eingeordnet werden. –

12

Ich weiß, dass dies eine sehr alte Frage, aber dieses fehlte hier:

Wenn Sie ReSharper verwenden Sie die Annotated Framework verwenden.

+1

Interessanterweise hat Ihre kompilierte Anwendung standardmäßig keinen Verweis auf die JetBrains.Annotations.dll, sodass Sie sie nicht mit der Anwendung verteilen müssen: [Verwendung von JetBrains-Anmerkungen zur Verbesserung der ReSharper-Inspektionen] (http: // blog .jetbrains.com/dotnet/2015/08/12/how-to-use-jetbrains-Anmerkungen zur Verbesserung der Nachschärfeinspektionen /) – Lu55

2

Ich weiß, ich bin unglaublich spät zu dieser Frage, aber ich denke, die Antwort wird relevant werden, wie die letzte große Iteration von C# kommt näher zu veröffentlichen, dann veröffentlicht. In C# 8.0 wird eine größere Änderung auftreten, C# wird annehmen, alle Typen werden als nicht null betrachtet.

Nach Mads Torgersen:

Das Problem ist, dass null Referenzen so nützlich sind. In C# sind sie der Standardwert jedes Referenztyps. Was wäre sonst der Standardwert ? Welchen anderen Wert würde eine Variable haben, bis Sie entscheiden können, was sie sonst noch zuweisen soll? Welchen anderen Wert könnten wir ein frisch zugewiesenes Array von Referenzen mit überlagern, bis Sie um ausfüllen es ausfüllen?

Manchmal ist null auch ein vernünftiger Wert an und für sich. Manchmal möchten Sie die Tatsache darstellen, dass, sagen wir, ein Feld keinen Wert hat. Es ist in Ordnung, "nichts" für einen Parameter zu übergeben. Die Betonung liegt jedoch manchmal auf . Und hierin liegt ein weiterer Teil des Problems: Sprachen wie C# lassen Sie nicht ausdrücken, ob eine Null hier eine gute Idee ist oder nicht.

So ist die Auflösung von Mads umrissen ist:

  1. Wir glauben, dass es häufiger ist eine Referenz zu wollen, nicht null zu sein. Nullable Referenztypen wäre die seltenere Art (obwohl wir keine guten Daten haben, um uns durch zu sagen, wie viel), so sind sie diejenigen, die eine neue Anmerkung benötigen sollten.

  2. Die Sprache hat bereits eine Vorstellung von - und einer Syntax für - Nullwerttypen. Die Analogie zwischen den beiden würde die Sprache konzeptionell einfacher und sprachlich einfacher machen.

  3. Es scheint richtig, dass Sie sich oder Ihre Verbraucher nicht mit umständlichen Nullwerten belasten sollten, es sei denn Sie haben aktiv entschieden, dass Sie sie wollen. Nullen, nicht die Abwesenheit von ihnen, sollte die Sache sein, die Sie explizit in aktivieren müssen.

Ein Beispiel für die gewünschte Funktion:

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

Die Vorschau für Visual Studio 2017 zur Verfügung steht, 15.5.4+ Vorschau.