Szkolenie
Moduł
Bezpieczeństwo zerowe w języku C# - Training
Poznaj praktyki kodowania, aby zapobiec wystąpieniu elementu NullReferenceException.
Ta przeglądarka nie jest już obsługiwana.
Przejdź na przeglądarkę Microsoft Edge, aby korzystać z najnowszych funkcji, aktualizacji zabezpieczeń i pomocy technicznej.
Wartość null w relacyjnej bazie danych jest używana, gdy wartość w kolumnie jest nieznana lub brakuje jej. Wartość null nie jest ciągiem pustym (dla typów danych znaków lub daty/godziny) ani wartością zerową (dla typów danych liczbowych). Specyfikacja ANSI SQL-92 stwierdza, że wartość null musi być taka sama dla wszystkich typów danych, dzięki czemu wszystkie wartości null są obsługiwane spójnie. System.Data.SqlTypes Przestrzeń nazw zapewnia semantykę o wartości null przez zaimplementowanie interfejsuINullable. Każdy z typów danych w programie System.Data.SqlTypes ma własną IsNull
Null
właściwość i wartość, którą można przypisać do wystąpienia tego typu danych.
Uwaga
Program .NET Framework w wersji 2.0 wprowadził obsługę typów wartości dopuszczających wartość null, co umożliwia programistom rozszerzenie typu wartości w celu reprezentowania wszystkich wartości bazowego typu. Te typy wartości dopuszczalnych do wartości CLR reprezentują wystąpienie Nullable struktury. Ta funkcja jest szczególnie przydatna, gdy typy wartości są w pudełku i bez skrzynki odbiorczej, co zapewnia lepszą zgodność z typami obiektów. Typy wartości dopuszczanych przez clR nie są przeznaczone do przechowywania wartości null bazy danych, ponieważ wartość null ANSI SQL nie zachowuje się tak samo jak null
odwołanie (lub Nothing
w Visual Basic). Do pracy z wartościami null SQL ANSI bazy danych użyj System.Data.SqlTypes wartości null, a nie Nullable. Aby uzyskać więcej informacji na temat pracy z typami dopuszczanymi wartości clR w języku Visual Basic, zobacz Typy wartości dopuszczalnych do wartości null, a w przypadku języka C# zobacz Typy wartości dopuszczanych do wartości null.
Zezwalanie na wartości null w definicjach kolumn wprowadza do aplikacji trzywartą logikę. Porównanie może ocenić jeden z trzech warunków:
Prawda
Fałsz
Nieznane
Ponieważ wartość null jest uważana za nieznaną, dwie wartości null w porównaniu ze sobą nie są uważane za równe. W wyrażeniach używających operatorów arytmetycznych, jeśli którykolwiek z operandów ma wartość null, wynik ma również wartość null.
Porównanie między dowolnym System.Data.SqlTypes elementem zwróci wartość SqlBoolean. Funkcja IsNull
dla każdego SqlType
zwraca wartość i SqlBoolean może służyć do sprawdzania wartości null. W poniższych tabelach prawdy pokazano, jak operatory AND, OR i NOT działają w obecności wartości null. (T=true, F=false i U=unknown lub null).
System.Data.SqlTypes udostępnia te same semantyki co w przypadku ustawienia opcji ANSI_NULLS w programie SQL Server. Wszystkie operatory arytmetyczne (+, -, *, /, %), operatory bitowe (~, &, |) i większość funkcji zwraca wartość null, jeśli którykolwiek z argumentów lub argumentów ma wartość null, z wyjątkiem właściwości IsNull
.
Standard ANSI SQL-92 nie obsługuje kolumny columnName = NULL w klauzuli WHERE. W programie SQL Server opcja ANSI_NULLS kontroluje zarówno domyślną wartość null w bazie danych, jak i ocenę porównań z wartościami null. Jeśli ANSI_NULLS jest włączona (wartość domyślna), operator IS NULL musi być używany w wyrażeniach podczas testowania wartości null. Na przykład następujące porównanie zawsze zwraca wartość nieznaną, gdy ANSI_NULLS jest włączona:
colname > NULL
Porównanie ze zmienną zawierającą wartość null daje również nieznane:
colname > @MyVariable
Użyj predykatu IS NULL lub IS NOT NULL, aby przetestować wartość null. Może to zwiększyć złożoność klauzuli WHERE. Na przykład kolumna TerritoryID w tabeli AdventureWorks Customer zezwala na wartości null. Jeśli instrukcja SELECT ma testować wartości null oprócz innych, musi zawierać predykat IS NULL:
SELECT CustomerID, AccountNumber, TerritoryID
FROM AdventureWorks.Sales.Customer
WHERE TerritoryID IN (1, 2, 3)
OR TerritoryID IS NULL
Jeśli ustawisz ANSI_NULLS wyłączone w programie SQL Server, możesz utworzyć wyrażenia, które używają operatora równości do porównania z wartością null. Nie można jednak uniemożliwić innym połączeniom ustawiania opcji null dla tego połączenia. Używanie wartości NULL IS do testowania wartości null zawsze działa, niezależnie od ANSI_NULLS ustawień połączenia.
Ustawienie ANSI_NULLS wyłączone nie jest obsługiwane w obiekcie , który zawsze jest zgodny ze standardem DataSet
ANSI SQL-92 do obsługi wartości null w programie System.Data.SqlTypes.
Wartości null są specjalne, a ich semantyka magazynu i przypisania różni się w różnych systemach typów i systemach magazynowania. Element jest Dataset
przeznaczony do użycia z różnymi typami i systemami magazynowania.
W tej sekcji opisano semantyka o wartościach null na potrzeby przypisywania wartości null do elementu DataColumn w DataRow różnych systemach typów.
DBNull.Value
To przypisanie jest prawidłowe dla DataColumn
dowolnego typu. Jeśli typ implementuje INullable
wartość , DBNull.Value
jest zmuszany do odpowiedniej silnie typizowanej wartości null.
SqlType.Null
Wszystkie System.Data.SqlTypes typy danych implementują wartość INullable
. Jeśli silnie typizowanej wartości null można przekonwertować na typ danych kolumny przy użyciu niejawnych operatorów rzutów, przypisanie powinno przejść. W przeciwnym razie jest zgłaszany nieprawidłowy wyjątek rzutu.
null
Jeśli wartość "null" jest wartością prawną dla danego DataColumn
typu danych, jest ona zmuszana do odpowiedniego DbNull.Value
lub Null
skojarzonego z typem INullable
(SqlType.Null
)
derivedUdt.Null
W przypadku kolumn UDT wartości null są zawsze przechowywane na podstawie typu skojarzonego z .DataColumn
Rozważmy przypadek udT skojarzonego z elementem DataColumn
, który nie implementuje INullable
, gdy jego podklasa nie działa. W takim przypadku, jeśli jest przypisana silnie typizowana wartość null skojarzona z klasą pochodną, jest przechowywana jako nietypowa DbNull.Value
, ponieważ magazyn o wartości null jest zawsze zgodny z typem danych dataColumn.
Uwaga
Struktura Nullable<T>
lub Nullable nie jest obecnie obsługiwana w pliku DataSet
.
Wartość domyślna dla dowolnego System.Data.SqlTypes wystąpienia ma wartość null.
Wartości null w obiekcie System.Data.SqlTypes są specyficzne dla typu i nie mogą być reprezentowane przez jedną wartość, taką jak DbNull
. Użyj właściwości , IsNull
aby sprawdzić, czy nie ma wartości null.
Wartości null można przypisać do elementu , DataColumn jak pokazano w poniższym przykładzie kodu. Możesz bezpośrednio przypisać wartości null do SqlTypes
zmiennych bez wyzwalania wyjątku.
Poniższy przykład kodu tworzy obiekt DataTable z dwiema kolumnami zdefiniowanymi jako SqlInt32 i SqlString. Kod dodaje jeden wiersz znanych wartości, jeden wiersz wartości null, a następnie iteruje za pośrednictwem DataTable, przypisując wartości do zmiennych i wyświetlając dane wyjściowe w oknie konsoli.
static void WorkWithSqlNulls()
{
DataTable table = new();
// Specify the SqlType for each column.
DataColumn idColumn =
table.Columns.Add("ID", typeof(SqlInt32));
DataColumn descColumn =
table.Columns.Add("Description", typeof(SqlString));
// Add some data.
DataRow nRow = table.NewRow();
nRow["ID"] = 123;
nRow["Description"] = "Side Mirror";
table.Rows.Add(nRow);
// Add null values.
nRow = table.NewRow();
nRow["ID"] = SqlInt32.Null;
nRow["Description"] = SqlString.Null;
table.Rows.Add(nRow);
// Initialize variables to use when
// extracting the data.
SqlBoolean isColumnNull = false;
SqlInt32 idValue = SqlInt32.Zero;
SqlString descriptionValue = SqlString.Null;
// Iterate through the DataTable and display the values.
foreach (DataRow row in table.Rows)
{
// Assign values to variables. Note that you
// do not have to test for null values.
idValue = (SqlInt32)row["ID"];
descriptionValue = (SqlString)row["Description"];
// Test for null value in ID column.
isColumnNull = idValue.IsNull;
// Display variable values in console window.
Console.Write("isColumnNull={0}, ID={1}, Description={2}",
isColumnNull, idValue, descriptionValue);
Console.WriteLine();
}
Private Sub WorkWithSqlNulls()
Dim table As New DataTable()
' Specify the SqlType for each column.
Dim idColumn As DataColumn = _
table.Columns.Add("ID", GetType(SqlInt32))
Dim descColumn As DataColumn = _
table.Columns.Add("Description", GetType(SqlString))
' Add some data.
Dim row As DataRow = table.NewRow()
row("ID") = 123
row("Description") = "Side Mirror"
table.Rows.Add(row)
' Add null values.
row = table.NewRow()
row("ID") = SqlInt32.Null
row("Description") = SqlString.Null
table.Rows.Add(row)
' Initialize variables to use when
' extracting the data.
Dim isColumnNull As SqlBoolean = False
Dim idValue As SqlInt32 = SqlInt32.Zero
Dim descriptionValue As SqlString = SqlString.Null
' Iterate through the DataTable and display the values.
For Each row In table.Rows
' Assign values to variables. Note that you
' do not have to test for null values.
idValue = CType(row("ID"), SqlInt32)
descriptionValue = CType(row("Description"), SqlString)
' Test for null value with ID column
isColumnNull = idValue.IsNull
' Display variable values in console window.
Console.Write("isColumnNull={0}, ID={1}, Description={2}", _
isColumnNull, idValue, descriptionValue)
Console.WriteLine()
Next row
End Sub
W tym przykładzie zostaną wyświetlone następujące wyniki:
isColumnNull=False, ID=123, Description=Side Mirror
isColumnNull=True, ID=Null, Description=Null
DataTable.Add
, DataTable.LoadDataRow
lub inne interfejsy API, które akceptują ItemArray element, który jest mapowany na wiersz, mapuje wartość "null" na wartość domyślną kolumny DataColumn. Jeśli obiekt w tablicy zawiera DbNull.Value
lub jego silnie typizowane odpowiedniki, stosowane są te same reguły, co opisane powyżej.
Ponadto dla wystąpienia DataRow.["columnName"]
przypisań o wartości null obowiązują następujące reguły:
Wartość domyślna dotyczy DbNull.Value
wszystkich z wyjątkiem silnie typiowanych kolumn null, gdzie jest to odpowiednia silnie typizowana wartość null.
Wartości null nigdy nie są zapisywane podczas serializacji do plików XML (jak w pliku "xsi:nil").
Wszystkie wartości inne niż null, w tym wartości domyślne, są zawsze zapisywane podczas serializacji do formatu XML. Jest to w przeciwieństwie do semantyki XSD/XML, gdzie wartość null (xsi:nil) jest jawna, a wartość domyślna jest niejawna (jeśli nie istnieje w formacie XML, analizator sprawdzania poprawności może pobrać go ze skojarzonego schematu XSD). Przeciwieństwem jest wartość true dla wartości DataTable
: wartość null jest niejawna, a wartość domyślna jest jawna.
Wszystkie brakujące wartości kolumn dla wierszy odczytanych z danych wejściowych XML mają przypisaną wartość NULL. Do wartości domyślnej kolumny DataColumn są przypisywane wiersze utworzone przy użyciu NewRow lub podobne metody.
Metoda IsNull zwraca true
wartość zarówno dla metody , jak DbNull.Value
i INullable.Null
.
Podczas porównywania wartości null ważne jest, aby zrozumieć różnicę między sposobem, w jaki Equals
metoda ocenia wartości null w porównaniu ze sposobem, w System.Data.SqlTypes jaki działa z typami CLR. System.Data.SqlTypesEquals
Wszystkie metody używają semantyki bazy danych do obliczania wartości null: jeśli albo obie wartości mają wartość null, porównanie daje wartość null. Z drugiej strony użycie metody CLR Equals
na dwóch System.Data.SqlTypes metodach zwróci wartość true, jeśli obie mają wartość null. Odzwierciedla to różnicę między użyciem metody wystąpienia, takiej jak metoda CLRString.Equals
, a użyciem metody statycznej/udostępnionej. SqlString.Equals
W poniższym przykładzie pokazano różnicę w wynikach między SqlString.Equals
metodą a String.Equals
metodą, gdy każda z nich jest przekazywana parę wartości null, a następnie parę pustych ciągów.
static void CompareNulls()
{
// Create two new null strings.
SqlString a = new();
SqlString b = new();
// Compare nulls using static/shared SqlString.Equals.
Console.WriteLine("SqlString.Equals shared/static method:");
Console.WriteLine(" Two nulls={0}", SqlStringEquals(a, b));
// Compare nulls using instance method String.Equals.
Console.WriteLine();
Console.WriteLine("String.Equals instance method:");
Console.WriteLine(" Two nulls={0}", StringEquals(a, b));
// Make them empty strings.
a = "";
b = "";
// When comparing two empty strings (""), both the shared/static and
// the instance Equals methods evaluate to true.
Console.WriteLine();
Console.WriteLine("SqlString.Equals shared/static method:");
Console.WriteLine(" Two empty strings={0}", SqlStringEquals(a, b));
Console.WriteLine();
Console.WriteLine("String.Equals instance method:");
Console.WriteLine(" Two empty strings={0}", StringEquals(a, b));
}
static string SqlStringEquals(SqlString string1, SqlString string2)
{
// SqlString.Equals uses database semantics for evaluating nulls.
var returnValue = SqlString.Equals(string1, string2).ToString();
return returnValue;
}
static string StringEquals(SqlString string1, SqlString string2)
{
// String.Equals uses CLR type semantics for evaluating nulls.
var returnValue = string1.Equals(string2).ToString();
return returnValue;
}
}
Private Sub CompareNulls()
' Create two new null strings.
Dim a As New SqlString
Dim b As New SqlString
' Compare nulls using static/shared SqlString.Equals.
Console.WriteLine("SqlString.Equals shared/static method:")
Console.WriteLine(" Two nulls={0}", SqlStringEquals(a, b))
' Compare nulls using instance method String.Equals.
Console.WriteLine()
Console.WriteLine("String.Equals instance method:")
Console.WriteLine(" Two nulls={0}", StringEquals(a, b))
' Make them empty strings.
a = ""
b = ""
' When comparing two empty strings (""), both the shared/static and
' the instance Equals methods evaluate to true.
Console.WriteLine()
Console.WriteLine("SqlString.Equals shared/static method:")
Console.WriteLine(" Two empty strings={0}", SqlStringEquals(a, b))
Console.WriteLine()
Console.WriteLine("String.Equals instance method:")
Console.WriteLine(" Two empty strings={0}", StringEquals(a, b))
End Sub
Private Function SqlStringEquals(ByVal string1 As SqlString, _
ByVal string2 As SqlString) As String
' SqlString.Equals uses database semantics for evaluating nulls.
Dim returnValue As String = SqlString.Equals(string1, string2).ToString()
Return returnValue
End Function
Private Function StringEquals(ByVal string1 As SqlString, _
ByVal string2 As SqlString) As String
' String.Equals uses CLR type semantics for evaluating nulls.
Dim returnValue As String = string1.Equals(string2).ToString()
Return returnValue
End Function
Kod generuje następujące dane wyjściowe:
SqlString.Equals shared/static method:
Two nulls=Null
String.Equals instance method:
Two nulls=True
SqlString.Equals shared/static method:
Two empty strings=True
String.Equals instance method:
Two empty strings=True
Szkolenie
Moduł
Bezpieczeństwo zerowe w języku C# - Training
Poznaj praktyki kodowania, aby zapobiec wystąpieniu elementu NullReferenceException.