c# - شرح - نوع nullable كمعلمة عامة ممكن؟




generics in c# شرح (7)

أعتقد أنك تريد التعامل مع أنواع المراجع وأنواع البنية. يمكنني استخدامه لتحويل سلاسل XML element إلى نوع مكتوب بشكل أكبر. يمكنك إزالة 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);

أريد أن أفعل شيئًا كهذا:

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

لاحظ نوع nullable كمعلمة عامة.

منذ أن GetValueOrNull الدالة 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;
}

لكن الخطأ الذي أتلقاه الآن هو:

نوع "كثافة العمليات؟" يجب أن يكون نوع مرجع لاستخدامه كمعلمة "T" في النوع أو الطريقة العامة

حق! Nullable<int> هي struct ! لذلك حاولت تغيير قيد الفئة إلى قيد struct (وحيث أن التأثير الجانبي لا يمكن أن null ):

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

الآن المهمة:

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

يعطي الخطأ التالي:

نوع "كثافة العمليات؟" يجب أن يكون نوع قيمة غير قابل للالغاء لاستخدامه كمعلمة "T" في النوع أو الطريقة العامة

هو تحديد نوع nullable كمعلمة عامة في كل شيء ممكن؟


أعلم أن هذا شيئ قديم ، لكن يوجد هنا حل آخر:

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);


فقط قم بشيئين إلى التعليمات البرمجية الأصلية - قم بإزالة where القيد ، وقم بتغيير آخر return من return null إلى return default(T) . بهذه الطريقة يمكنك إرجاع أي نوع تريده.

بالمناسبة ، يمكنك تجنب استخدام عن طريق تغيير العبارة if (columnValue != DBNull.Value) .


فقط كان عليه أن يفعل شيئًا مذهلاً مشابهًا لهذا. رمز بلدي:

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;
}

لا يمكن الجمع بين قيود عامة متعددة بطريقة OR (أقل تقييدًا) ، فقط بطريقة AND AND (أكثر تقييدًا). بمعنى أن هناك طريقة واحدة لا تستطيع التعامل مع كل من السيناريوهات. لا يمكن أيضًا استخدام القيود العامة لإنشاء توقيع فريد للطريقة ، لذلك يجب عليك استخدام اسمين منفصلين للطريقة.

ومع ذلك ، يمكنك استخدام قيود عام للتأكد من استخدام الأساليب بشكل صحيح.

في حالتي ، أردت تحديدًا أن يتم إرجاع null ، وألا تكون القيمة الافتراضية لأي أنواع قيم ممكنة. GetValueOrDefault = سيئة. GetValueOrNull = جيد.

لقد استخدمت الكلمتين "Null" و "Nullable" للتمييز بين أنواع المرجع وأنواع القيم. وإليك مثالاً عن أساليب ملحق الزوجية التي كتبتها تكمل أسلوب FirstOrDefault في فئة System.Linq.Enumerable.

    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;
    }

لقد واجهت نفس المشكلة بنفسي.

... = reader["myYear"] as int?; يعمل ونظيفة.

يعمل مع أي نوع دون مشكلة. إذا كانت النتيجة هي DBNull ، فإنها تُرجع فارغة حيث فشل التحويل.


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