Ну, я получил ответ, пытаясь просто вернуться
return Json("",JsonRequestBehavior.AllowGet);
, и мы готовы пойти на успешный ответ Ajax.
Можно просто объявить метод как это:
public static T GetNullable<T>(this IDataRecord dr, int ordinal)
{
return dr.IsDBNull(ordinal) ? default(T) : (T) dr.GetValue(ordinal);
}
Таким образом, если T является nullable интервалом или каким-либо другим nullable типом значения, он на самом деле возвратит пустой указатель. Если это будет регулярный тип данных, то это просто возвратит значение по умолчанию для того типа.
Это работает:
public static T Get<T>( this IDataRecord dr, int ordinal)
{
T nullValue = default(T);
return dr.IsDBNull(ordinal) ? nullValue : (T) dr.GetValue(ordinal);
}
public void Code(params string[] args)
{
IDataRecord dr= null;
int? a = Get<int?>(dr, 1);
string b = Get<string>(dr, 2);
}
Я не думаю, что можно реализовать это с единственной функцией. Если бы C# поддерживал перегрузку на основе типа возврата, Вы смогли, но даже затем я рекомендовал бы против выполнения так.
Необходимо смочь выполнить то же самое, не используя nullable типы данных и возвратить или фактическое значение или пустой указатель, как предложено BFree.
Вы не можете сделать этого с одним методом, но Вы делаете это с три:
public static T GetData<T>(this IDataReader reader, Func<int, T> getFunc, int index)
{
if (!reader.IsClosed)
{
return getFunc(index);
}
throw new ArgumentException("Reader is closed.", "reader");
}
public static T GetDataNullableRef<T>(this IDataReader reader, Func<int, T> getFunc, int index) where T : class
{
if (!reader.IsClosed)
{
return reader.IsDBNull(index) ? null : getFunc(index);
}
throw new ArgumentException("Reader is closed.", "reader");
}
public static T? GetDataNullableValue<T>(this IDataReader reader, Func<int, T> getFunc, int index) where T : struct
{
if (!reader.IsClosed)
{
return reader.IsDBNull(index) ? (T?)null : getFunc(index);
}
throw new ArgumentException("Reader is closed.", "reader");
}
Затем для использования его Вы сделали бы:
private static Whatever CreateObject(IDataReader reader)
{
Int32? id = reader.GetDataNullableValue<Int32>(reader.GetInt32, 0);
string name = reader.GetDataNullableRef<string>(reader.GetString, 1);
Int32 x = reader.GetData<Int32>(reader.GetInt32, 2);
}
Я делаю это этот путь:
DataRow record = GetSomeRecord();
int? someNumber = record[15] as int?
Guid? someUID = record["MyPrimaryKey"] as Guid?;
string someText = GetSomeText();
record["Description"] = someText.ToDbString();
// ........
public static class StringExtensionHelper {
public static object ToDbString( this string text ) {
object ret = null != text ? text : DBNull.Value
return ret;
}
}
Править: Вы можете (или Вы должны) иметь "ToDbInt32, ToDbBool, и т.д...." дополнительные методы для других типов примитивов, конечно.
РЕДАКТИРОВАНИЕ 2: можно также расширить базовый класс "объект" с помощью "ToDbValue".
public static class StringExtensionHelper {
public static object ToDbValue( this object value ) {
object ret = object.ReferenceEquals( value, null ) ? (object)DBNull.Value : value;
return ret;
}
}
Структура Nullable только для типов Значения, потому что ссылочные типы nullable так или иначе...
public static T Get<T>(this IDataRecord rec, Func<int, T> GetValue, int ordinal)
{
return rec.IsDBNull(ordinal) ? default(T) : GetValue(ordinal);
}
или более высокая производительность
public static T Get<T>(this IDataRecord rec, Func<IDataRecord, int, T> GetValue, int ordinal)
{
return rec.IsDBNull(ordinal) ? default(T) : GetValue(rec, ordinal);
}
public static Func<IDataRecord, int, int> GetInt32 = (rec, i) => rec.GetInt32(i);
public static Func<IDataRecord, int, bool> GetBool = (rec, i) => rec.GetBoolean(i);
public static Func<IDataRecord, int, string> GetString = (rec, i) => rec.GetString(i);
и используйте его так
rec.Get(GetString, index);
rec.Get(GetInt32, index);
Я не могу понять, зачем нужно усложнять весь этот процесс. Почему бы не сделать все просто и понятно и не использовать следующие строки кода:
Для типов значений, где null допустим, используйте int? iNullable = dr[ordinal] as int?;
.
Для типов значений, где null недопустим, используйте int iNonNullable = dr[ordinal] as int? ?? default(int);
.
Для ссылочных типов используйте string sValue = dr[ordinal] as string;
.
Для тех, кто думает, что код не будет работать и что dr[ordinal]
выбросит исключение для DBNull, приводим пример метода, который, получив корректную строку подключения, докажет концепцию.
private void Test()
{
int? iTestA;
int? iTestB;
int iTestC;
string sTestA;
string sTestB;
//Create connection
using (SqlConnection oConnection = new SqlConnection(@""))
{
//Open connection
oConnection.Open();
//Create command
using (SqlCommand oCommand = oConnection.CreateCommand())
{
//Set command text
oCommand.CommandText = "SELECT null, 1, null, null, '1'";
//Create reader
using (SqlDataReader oReader = oCommand.ExecuteReader())
{
//Read the data
oReader.Read();
//Set the values
iTestA = oReader[0] as int?;
iTestB = oReader[1] as int?;
iTestC = oReader[2] as int? ?? -1;
sTestA = oReader[3] as string;
sTestB = oReader[4] as string;
}
}
}
}