c# - 형식 - 가능한 일반 매개 변수로 Nullable 유형?




c# 형식 매개변수 (7)

나는 이것이 오래되었음을 알고 있지만 여기에 또 다른 해결책이있다.

public static bool GetValueOrDefault<T>(this SqlDataReader Reader, string ColumnName, out T Result)
{
    try
    {
        object ColumnValue = Reader[ColumnName];

        Result = (ColumnValue!=null && ColumnValue != DBNull.Value) ? (T)ColumnValue : default(T);

        return ColumnValue!=null && ColumnValue != DBNull.Value;
    }
    catch
    {
        // Possibly an invalid cast?
        return false;
    }
}

이제 T 가 가치 또는 참조 유형인지는 상관하지 않습니다. 이 함수가 true를 반환하는 경우에만 데이터베이스에서 적절한 값을 얻습니다. 용법:

...
decimal Quantity;
if (rdr.GetValueOrDefault<decimal>("YourColumnName", out Quantity))
{
    // Do something with Quantity
}

이 접근법은 int.TryParse("123", out MyInt); 와 매우 유사합니다 int.TryParse("123", out MyInt);

나는 이런 식으로하고 싶다.

myYear = record.GetValueOrNull<int?>("myYear"),

nullable 형식을 제네릭 매개 변수로 확인하십시오.

GetValueOrNull 함수가 null을 반환 할 수 있기 때문에 첫 번째 시도는 다음과 같습니다.

public static T GetValueOrNull<T>(this DbDataRecord reader, string columnName)
  where T : class
{
    object columnValue = reader[columnName];

    if (!(columnValue is DBNull))
    {
        return (T)columnValue;
    }
    return null;
}

하지만 지금 오류가 발생했습니다 :

'int?'유형입니다. 제네릭 형식 또는 메서드에서 매개 변수 'T'로 사용하려면 참조 형식이어야합니다.

권리! Nullable<int> struct ! 그래서 클래스 제약 조건을 struct 제약 조건으로 변경하려고 시도했습니다. 부작용은 더 이상 null 반환 할 수 없습니다.

public static T GetValueOrNull<T>(this DbDataRecord reader, string columnName)
  where T : struct

이제 과제 :

myYear = record.GetValueOrNull<int?>("myYear");

다음 오류를 제공합니다.

'int?'유형입니다. 제네릭 형식 또는 메서드에서 매개 변수 'T'로 사용하려면 nullable이 아닌 값 형식이어야합니다.

가능한 모든 범용 매개 변수로 nullable 형식을 지정하고 있습니까?


난 당신이 참조 유형 및 구조체 유형을 처리하려는 것 같아요. XML 요소 문자열을 더 형식이 지정된 형식으로 변환하는 데 사용합니다. 리플렉션을 사용하여 nullAlternative를 제거 할 수 있습니다. formatprovider는 문화에 따라 달라지는 '.' 또는 ','분리 기호 (예 : 십진수 또는 정수 및 복식). 이것은 작동 할 수 있습니다 :

public T GetValueOrNull<T>(string strElementNameToSearchFor, IFormatProvider provider = null ) 
    {
        IFormatProvider theProvider = provider == null ? Provider : provider;
        XElement elm = GetUniqueXElement(strElementNameToSearchFor);

        if (elm == null)
        {
            object o =  Activator.CreateInstance(typeof(T));
            return (T)o; 
        }
        else
        {
            try
            {
                Type type = typeof(T);
                if (type.IsGenericType &&
                type.GetGenericTypeDefinition() == typeof(Nullable<>).GetGenericTypeDefinition())
                {
                    type = Nullable.GetUnderlyingType(type);
                }
                return (T)Convert.ChangeType(elm.Value, type, theProvider); 
            }
            catch (Exception)
            {
                object o = Activator.CreateInstance(typeof(T));
                return (T)o; 
            }
        }
    }

다음과 같이 사용할 수 있습니다.

iRes = helper.GetValueOrNull<int?>("top_overrun_length");
Assert.AreEqual(100, iRes);



decimal? dRes = helper.GetValueOrNull<decimal?>("top_overrun_bend_degrees");
Assert.AreEqual(new Decimal(10.1), dRes);

String strRes = helper.GetValueOrNull<String>("top_overrun_bend_degrees");
Assert.AreEqual("10.1", strRes);

방금 같은 문제가 발생했습니다.

... = reader["myYear"] as int?; 작동하며 깨끗합니다.

모든 유형의 문제없이 작동합니다. 결과가 DBNull이면 변환에 실패 할 때 null을 반환합니다.


여러 일반 제 약 조건은 OR 방식 (덜 제한적)으로 결합 될 수 없으며 AND 방식 (더 제한적)으로 만 결합 될 수 있습니다. 한 가지 방법으로 두 시나리오를 처리 할 수 ​​없다는 것을 의미합니다. 제네릭 제약 조건은 메서드에 고유 한 서명을 만드는 데 사용할 수 없으므로 두 개의 별도 메서드 이름을 사용해야합니다.

그러나 제네릭 제약 조건을 사용하여 메서드가 올바르게 사용되는지 확인할 수 있습니다.

필자의 경우, null 값이 리턴되기를 원했고, 가능한 값 유형의 기본값이 결코 아니었다. GetValueOrDefault = 좋지 않습니다. GetValueOrNull = 좋습니다.

참조 유형과 값 유형을 구별하기 위해 "Null"및 "Nullable"이라는 단어를 사용했습니다. 다음은 System.Linq.Enumerable 클래스의 FirstOrDefault 메서드를 사용하여 작성한 몇 가지 확장 메서드의 예입니다.

    public static TSource FirstOrNull<TSource>(this IEnumerable<TSource> source)
        where TSource: class
    {
        if (source == null) return null;
        var result = source.FirstOrDefault();   // Default for a class is null
        return result;
    }

    public static TSource? FirstOrNullable<TSource>(this IEnumerable<TSource?> source)
        where TSource : struct
    {
        if (source == null) return null;
        var result = source.FirstOrDefault();   // Default for a nullable is null
        return result;
    }

이 작업과 비슷한 놀라운 작업을 수행해야했습니다. 내 코드 :

public T IsNull<T>(this object value, T nullAlterative)
{
    if(value != DBNull.Value)
    {
        Type type = typeof(T);
        if (type.IsGenericType && 
            type.GetGenericTypeDefinition() == typeof(Nullable<>).GetGenericTypeDefinition())
        {
            type = Nullable.GetUnderlyingType(type);
        }

        return (T)(type.IsEnum ? Enum.ToObject(type, Convert.ToInt32(value)) :
            Convert.ChangeType(value, type));
    }
    else 
        return nullAlternative;
}

이것은 죽은 스레드 일지 모르지만 다음을 사용하는 경향이 있습니다.

public static T? GetValueOrNull<T>(this DbDataRecord reader, string columnName)
where T : struct 
{
    return reader[columnName] as T?;
}

public static T GetValueOrDefault<T>(this IDataRecord rdr, int index)
{
    object val = rdr[index];

    if (!(val is DBNull))
        return (T)val;

    return default(T);
}

다음과 같이 사용하십시오.

decimal? Quantity = rdr.GetValueOrDefault<decimal?>(1);
string Unit = rdr.GetValueOrDefault<string>(2);




generics