Frage

Ich habe die folgende Erweiterungsmethode gemacht ...

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

..., die ich für beispielsweise verwenden Lesen von Daten wie folgt:

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

Aber es funktioniert nicht, wenn ich von einem Box-Wert auf eine Nullable-Enumeration Guss will. Das Beste, was ich tun konnte, war diesen (unordentlich WIP-Code, der nicht funktioniert):

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

Verbrauch:

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

Der aktuelle Fehler ist ein InvalidCastException, wenn es versucht, eine Int32 zur Nullable-Enumeration zu werfen. Welches ist ok i guess, aber ich habe keine Ahnung, wie ich sonst noch tun könnte? Ich habe versucht, eine Instanz der Nullable-Enumeration T und weisen Sie ihm einen Wert zu schaffen, aber ich bin fest, wie genau dies geschehen kann.

Wer eine Idee oder ein besserer Weg, dieses Problem zu lösen? Ist es sogar möglich, dass in allgemeiner Weise zu lösen? Ich habe ziemlich viel getan auf dem von der Suche, aber ich habe nichts gefunden nützlich.

War es hilfreich?

Lösung

Sie können es tun, indem Sie den Konstruktor für die Nullable Type Aufruf Sie benötigen. Wie folgt aus:

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

Andere Tipps

Mit Hans' Antwort war ich in der Lage, es zu bekommen arbeiten und wenn jemand interessiert ist hier die feste Version:

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

Aber die zusätzlichen Prüfungen / Code für die Nullable-Enumeration verletzt Leistung für alle anderen Arten. Vor der Erweiterung Methode ~ war 2-3 langsamer, jetzt ist es ~ 10-15 mal. Doing it 1000000 (Mio.) mal mit dem Code oben:

Unboxing int: 4 ms
Unboxing int mit Erweiterungsmethode: 59ms (vor ohne Pflege von Nullable-Enumeration unter: 12ms)
Unboxing auf NULL festlegbare Enum: 5ms
Unboxing auf NULL festlegbare Enum mit Erweiterungsmethode: 3382ms

Also, auf diesen Zahlen sucht diese Methoden nicht die erste Wahl sein sollen, wenn die Leistung entscheidend ist -. Zumindest nicht, wenn es für Nullable-Aufzählungen mit

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top