Тест для нулевых значений в C # - PullRequest
12 голосов
/ 08 июня 2011

Если я сделаю что-то вроде:

DataSet ds = GetMyDataset();

try
{
    string somevalue = ds.Tables[0].Rows[0]["col1"];
}
catch
{
    //maybe something was null
}

Есть ли хороший способ проверить нулевые значения без использования try / catch?Просто мне все равно, если значение в "col1" равно нулю, ИЛИ, если "col1" не существует, ИЛИ, если не было возвращенных строк, ИЛИ, если таблица не существует!

Может, мне все равно?:) Может быть, попытка / ловить это лучший способ приблизиться к этому, но я просто подумал, есть ли другой способ сделать это?

Спасибо!

Ответы [ 14 ]

7 голосов
/ 08 июня 2011

Странно не заботиться о Столе или Колонке.

Это гораздо более нормальная практика, например, ожидать table[0].Rows.Count == 0.

И лучший способ проверить значения NULL - if(...) ... else ....
Худший способ - ждать исключений (любым способом).

4 голосов
/ 08 июня 2011
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...
...
3 голосов
/ 08 июня 2011

Если вы хотите убедиться, что ваш код не выйдет из строя, вам действительно нужно будет проверить все элементы в иерархии, например:

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"];
}
2 голосов
/ 08 июня 2011
DataSet ds = GetMyDataset();

string somevalue = ds != null ? ds.Tables[0].Rows[0]["col1"].ToString() : null;
1 голос
/ 08 июня 2011

Сделайте несколько проверок:

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();
                }
            }
        }
1 голос
/ 08 июня 2011

вы могли бы использовать термин «nullabel», но я думаю, что возвращаемое значение NULL - это «DBNull», а не «NULL».

Примером будет ...

string somevalue = ds.Tables[0].Rows[0]["col1"] ?? "";
0 голосов
/ 08 июня 2011

Я ненавижу иметь дело со слоем доступа к данным, который не гарантирует мне стандартный набор результатов: любой данный запрос SQL или хранимая процедура должны всегда возвращать одну и ту же схему набора результатов. Работать с пустыми наборами (или 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 значений, вы можете легко увидеть, что присутствовало, а что отсутствовало. Это позволяет легко увидеть, какое предположение (ограничение?) Было нарушено.

0 голосов
/ 08 июня 2011

Если вы действительно отправляете случайные, не проверенные наборы данных, индексы и имена, вы можете использовать вспомогательный метод, подобный этому:

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").

0 голосов
/ 08 июня 2011

Я думаю, Может быть, Монада лучше всего подходит для этой ситуации (пример из источника):

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, смотрите ссылку.

0 голосов
/ 08 июня 2011

Я думаю, вы должны четко заявить, что вас не волнуют все эти вещи, а это означает, что вы должны обращаться с каждым случаем явно:

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"]

Это больше кода, но для меня он более четко сообщает о намерениях.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...