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

У меня есть некоторые вызовы кода уровня доступа к данным сохраненный proc, и возвращает скалярные значения различных типов данных. Синтаксисом является ExecuteDecimal, ExecuteString, и т.д. Я хочу, чтобы это было Execute<string> или Execute<decimal>

Я пробую эту реализацию, и я не могу скомпилировать, если я не делаю кастинг с помощью" (T) значение", если я пытаюсь проверить тип и назвать метод, чтобы сделать кастинг, никакую такую удачу.

ОБНОВЛЕННЫЙ вопрос, Почему я должен преобразовать в объект прежде, чем преобразовать в T?

ОБНОВЛЕННЫЙ код

internal T Execute<T>(string storedProcName, Hashtable parameters)
{
      //Next lines do compile (thanks to suggestions from answers!)
      if (typeof(T) == typeof(string))
          return (T) (object) ExecuteScalar(storedProcName, parameters).ToString();
      else if (typeof(T) == typeof(int))
          return (T)(object) Convert.ToInt32(ExecuteScalar(storedProcName, parameters));
      //Next line compiles, but not all things boxed in an object can
      //be converted straight to type T (esp db return values that might contain DbNull.Value, etc)
      return (T)ExecuteScalar(storedProcName, parameters);
}
7
задан Joel Coehoorn 4 June 2010 в 18:05
поделиться

4 ответа

Попробуйте следующее:

var result = ExecuteScalar(storedProcName, parameters);
if(Convert.IsDBNull(result))
    return default(T);
if(result is T) // just unbox
    return (T)result;
else            // convert
    return (T)Convert.ChangeType(result, typeof(T));

Обновлено : исправлена ​​обработка DBNull

11
ответ дан 6 December 2019 в 19:33
поделиться

Возможно, вместо этого ваша функция могла бы быть изменена, чтобы разрешить передачу функции преобразования объекта:

internal T Execute<T>(string storedProcName, Hashtable parameters, Func<object, T> resultConverter)
{
}

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

internal string ExecuteForString(string storedProcName, Hashtable parameters)
{
    return Execute(storedProcName, parameters, (o) => o.ToString());
}

internal int ExecuteForInt(string storedProcName, Hashtable parameters)
{
     return Execute(storedProcName, parameters, Convert.ToInt32);
}

В в случае ваших проверок DBNull вы можете либо вернуть default (T) , либо добавить другую перегрузку для передачи значения по умолчанию, если возвращается DBNull - например, в случае int может быть лучше вернуть -1 вместо 0.

0
ответ дан 6 December 2019 в 19:33
поделиться
typeof(T) == typeof(string)

и для проверки нулевого значения по DBNull.Value

общий метод:

internal T Execute<T>(string storedProcName, Hashtable parameters)
{
      object res = ExecuteScalar(storedProcName, parameters);
      if (Convert.IsDBNull(res))
         return default(T); //or handle somehow
      return (T)Convert.ChangeType(res, typeof(T));
}
1
ответ дан 6 December 2019 в 19:33
поделиться

попробуйте ключевое слово 'as'

object o = ExecuteScalar(storedProcName, parameters);
string s;
int i;
// .. more

if ((s = o as string) != null)
{
  return s;
}
if ((i = o as int?) != null) // can't use as for value types, so use nullable
{
  return Convert.ToInt32(o);
}
return o as T;
1
ответ дан 6 December 2019 в 19:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: