سؤال

لقد صنعت طريقة التمديد التالية ...

public static class ObjectExtensions
{
    public static T As<T>(this object pObject, T pDefaultValue)
    {
        if (pObject == null || pObject == DBNull.Value)
            return pDefaultValue;
        return (T) pObject;
    }
}

... التي أستخدمها في قراءة بيانات مثل ذلك:

string field = datareader["column"].As("default value when null")

لكن هذا لا يعمل عندما أرغب في إلقاء نظرة لاغية من قيمة محاصر. أفضل ما يمكن أن أتوصل إليه هو هذا (رمز WIP الفوضوي الذي لا يعمل):

public static class ObjectExtensions
{
    public static T As<T>(this object pObject, T pDefaultValue)
    {
        if (pObject == null || pObject == DBNull.Value)
            return pDefaultValue;

        var lType = typeof (T);

        if (!IsNullableEnum(lType))
            return (T) pObject;

        var lEnumType = Nullable.GetUnderlyingType(lType);
        var lEnumPrimitiveType = lEnumType.GetEnumUnderlyingType();

        if (lEnumPrimitiveType == typeof(int))
        {
            var lObject = (int?) pObject;
            return (T) Convert.ChangeType(lObject, lType);
        }

        throw new InvalidCastException();
    }

    private static bool IsNullableEnum(Type pType)
    {
        Type lUnderlyingType = Nullable.GetUnderlyingType(pType);
        return (lUnderlyingType != null) && lUnderlyingType.IsEnum;
    }
}

الاستخدام:

public enum SomeEnum {Value1, Value2};
object value = 1;
var result = value.As<SomeEnum?>();

الخطأ الحالي هو بمثابة InvalidCastexception عندما يحاول إلقاء int32 على التعداد الباطئ. ما هو جيد على ما أعتقد ، لكن ليس لدي أي فكرة عن كيفية فعل ذلك؟ لقد حاولت إنشاء مثيل من التعداد البارز وتعيين قيمة ، لكنني عالق في كيفية القيام بذلك بالضبط.

أي شخص فكرة أو أفضل طريقة لحل هذا؟ هل من الممكن حل ذلك بطريقة عامة؟ لقد فعلت الكثير من البحث عن ذلك ، لكنني لم أجد أي شيء مفيد.

هل كانت مفيدة؟

المحلول

يمكنك القيام بذلك عن طريق استدعاء مُنشئ النوع الذي تحتاجه. مثله:

            Type t = typeof(Nullable<>).MakeGenericType(lEnumType);
            var ctor = t.GetConstructor(new Type[] { lEnumType });
            return (T)ctor.Invoke(new object[] { pObject });

نصائح أخرى

مع إجابة هانز ، تمكنت من العمل ، وإذا كان أي شخص مهتمًا ، فهذا الإصدار الثابت:

public static class ObjectExtensions
{
    private static Dictionary<Type, ConstructorInfo> _NullableEnumCtor = new Dictionary<Type, ConstructorInfo>();

    public static T As<T>(this object pObject)
    {
        return As(pObject, default(T));
    }

    public static T As<T>(this object pObject, T pDefaultValue)
    {
        if (pObject == null || pObject == DBNull.Value)
            return pDefaultValue;

        var lObjectType = pObject.GetType();
        var lTargetType = typeof(T);

        if (lObjectType == lTargetType)
            return (T) pObject;

        var lCtor = GetNullableEnumCtor(lTargetType);
        if (lCtor == null)
            return (T) pObject;

        return (T)lCtor.Invoke(new[] { pObject });
    }

    private static ConstructorInfo GetNullableEnumCtor(Type pType)
    {
        if (_NullableEnumCtor.ContainsKey(pType))
            return _NullableEnumCtor[pType];

        var lUnderlyingType = Nullable.GetUnderlyingType(pType);
        if (lUnderlyingType == null || !lUnderlyingType.IsEnum)
        {
            lock (_NullableEnumCtor) { _NullableEnumCtor.Add(pType, null); }
            return null;
        }

        var lNullableType = typeof(Nullable<>).MakeGenericType(lUnderlyingType);
        var lCtor = lNullableType.GetConstructor(new[] { lUnderlyingType });

        lock (_NullableEnumCtor) { _NullableEnumCtor.Add(pType, lCtor); }
        return lCtor;
    }
}

لكن الفحوصات/الرمز الإضافي للعدوى الباطلة تؤذي الأداء لجميع الأنواع الأخرى. قبل أن كانت طريقة التمديد أبطأ ~ 2-3 ، الآن 10-15 مرة. القيام بذلك 1000000 (مليون) باستخدام الكود أعلاه:

unboxing int: 4ms
unboxing int باستخدام طريقة التمديد: 59 مللي ثانية (قبل دون رعاية Nullable enum: 12ms)
unboxing to nullable enum: 5ms
unboxing to nullable enum باستخدام طريقة التمديد: 3382 مللي ثانية

لذلك ، لا ينبغي أن يكون النظر في هذه الأرقام هذه الأساليب هو الخيار الأول عندما يكون الأداء أمرًا بالغ الأهمية - على الأقل ليس عند استخدامه للعدادات البارزة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top