Проверка нулевых значений в С#
Если я сделаю что-то вроде:
DataSet ds = GetMyDataset();
try
{
string somevalue = ds.Tables[0].Rows[0]["col1"];
}
catch
{
//maybe something was null
}
Есть ли хороший способ проверить нулевые значения без использования try/catch? Это просто, что мне все равно, если значение в "col1" равно null, или если "col1" не существует, или если не было возвращенных строк, OR, если таблица не существует!
Может, мне все равно?:)
Может быть, try/catch - лучший способ приблизиться к этому, но я просто задавался вопросом, есть ли другой способ сделать это?
Спасибо!
Ответы
Ответ 1
Я думаю, Может быть, Монада лучше всего подходит для этой ситуации (Образец из источника):
public static TResult With<TInput, TResult>(this TInput o,
Func<TInput, TResult> evaluator)
where TResult : class where TInput : class
{
if (o == null) return null;
return evaluator(o);
}
string postCode = this.With(x => person)
.With(x => x.Address)
.With(x => x.PostCode)
для вашего случая похоже на:
ds.With(x=>Tables[0]).With(x=>x.Rows).With(x=>x[0])...
вы создадите класс расширения и будете использовать его, не беспокоясь о нулевых ссылках. Также метод Return
полезен для ссылки на ссылку.
Ответ 2
Это странно, если не заботиться о Столе или Столбе.
Это гораздо более обычная практика, например, ожидать table[0].Rows.Count == 0
.
И лучший способ проверить значения NULL - if(...) ... else ...
.
Хуже всего ждать Exceptions (каким бы то ни было способом).
Ответ 3
if (ds == null
|| ds.Tables == null
|| ds.Tables.Count == 0
|| ds.Tables[0].Rows == null
|| ds.Tables[0].Rows.Count == 0
|| ds.Tables[0].Rows[0].IsNull("col1")
)
//there is no data...
...
Ответ 4
Если вы хотите убедиться, что ваш код не будет работать, вам действительно нужно будет проверить все элементы в иерархии, например:
string someValue = "";
if (ds != null &&
ds.Tables != null &&
ds.Tables.Any() &&
ds.Tables[0].Rows != null &&
ds.Tables[0].Rows.Any() &&
ds.Tables[0].Rows[0]["col1"] != DBNull.Value)
{
someValue = ds.Tables[0].Rows[0]["col1"];
}
Ответ 5
DataSet ds = GetMyDataset();
string somevalue = ds != null ? ds.Tables[0].Rows[0]["col1"].ToString() : null;
Ответ 6
вы могли бы использовать nullabel terinary '??', но я думаю, что возвращаемое значение null является "DBNull", а не "null".
Пример будет...
string somevalue = ds.Tables[0].Rows[0]["col1"] ?? "";
Ответ 7
Сделайте несколько проверок:
string somevalue = String.Empty;
if (ds.Tables.Count > 0)
{
System.Data.DataTable dt = ds.Tables[0];
if (dt.Rows.Count > 0)
{
System.Data.DataRow dr = dt.Rows[0];
if (dt.Columns.Count>0 && dt.Columns.Contains("col1"))
{
somevalue = dr["col1"].ToString();
}
}
}
Ответ 8
Вам нужно будет проверить их все для нулевого (или других типов нулей) один за другим, начиная с вершины (который является DataSet)
if (ds!= null)
if (table!= null)
...
вы можете сделать это без, но ваш код будет намного более восприимчивым к ошибкам.
Ответ 9
С точки зрения обслуживания, то, что вы делаете, очень желательно.
В противном случае вам необходимо: проверить, является ли DS нулевым, проверить, есть ли какие-либо таблицы в DataSet, проверить, есть ли какие-либо строки в таблице, проверить, существует ли столбец, проверить, есть ли если в столбце есть какие-либо данные.
Это, безусловно, устранит много утомительного кода.
Ответ 10
То, что я использовал в прошлом, представляет собой небольшую оболочку тестов Null, которые возвращают значение по умолчанию. Например:
/// <summary>
/// Test DBValue for DBNull and return NullReplaceValue if DBValue is DBNull
/// </summary>
/// <returns>Returns NullReplaceValue if DBValue is DBNull</returns>
public static string NullStr(object DBValue, string NullReplaceValue)
{
if (object.ReferenceEquals(DBValue, DBNull.Value)) {
return NullReplaceValue;
} else {
return Convert.ToString(DBValue);
}
}
При использовании:
string somevalue = MyNullTests.NullStr(ds.Tables[0].Rows[0]["col1"], "Value was null");
Ответ 11
Я думаю, вы должны четко указать, что вы не заботитесь обо всех этих вещах, а это означает, что вы должны обрабатывать каждый случай явно:
if (ds.Tables.Count == 0)
return null;
var table = ds.Tables[0];
if (table.Rows.Count == 0)
return null;
if (!table.Columns.Contains("col1"))
return null;
var row = ds.Rows[0];
if (row.IsNull("col1"))
return null;
return row["col1"]
Это больше кода, но для меня он более четко передает намерение.
Ответ 12
Если вы действительно отправляете случайные, не проверенные наборы данных, индексы и имена, вы можете использовать вспомогательный метод, подобный этому:
public static Object GetDataSetValue(DataSet dataSet, int tableIndex, int rowIndex, string columnName)
{
Object value = null;
if (dataSet != null
&& tableIndex >= 0
&& tableIndex < dataSet.Tables.Count
&& rowIndex >= 0
&& rowIndex < dataSet.Tables[tableIndex].Rows.Count
&& dataSet.Tables[tableIndex].Columns.Contains(columnName))
{
value = dataSet.Tables[tableIndex].Rows[rowIndex][columnName];
}
return value;
}
А потом просто используйте что-то вроде GetDataSetValue(ds, 0, 0, "col1")
.
Ответ 13
Мне не нравится иметь дело с уровнем доступа к данным, который не гарантирует мне стандартный набор результатов: любой SQL-запрос или хранимая процедура должны всегда возвращать одну и ту же схему набора результатов. Работа с пустыми наборами (aka DataTables) проста. Работа с любыми отсутствующими ссылками на объекты... не так много.
Правильный ответ - исправить код доступа к данным, чтобы он возвращал согласованную схему.
В противном случае, если мне приходится иметь дело с таким кодом, я делаю что-то вроде этого:
DataSet ds = ExecuteStoredProcedure();
DataTable dt = ( ds != null && ds.Tables != null ? ds.Tables[0] : null ) ;
DataRow dr = ( dt != null && dt.Rows != null ? dt.Rows[0] : null ) ;
object o = ( dr != null ? dr["someColumn"]) : null ) ;
string someColumn = (string) colName ;
Легко отлаживать либо в отладчике, либо путем ведения журнала. Дайте набор из 5 значений, вы можете легко увидеть, что присутствовало и чего не хватало. Это позволяет легко понять, какое предположение (ограничение?) Было нарушено.
Ответ 14
Вы проверяете DBNull.Value, например,
if (ds.Tables[0].Rows[0]["col1"] != DBNull.Value)