2016-07-26 12 views
0

Ich schreibe eine Serializer-Klasse und ich versuche, eine Funktion zu schreiben, um jede Enumeration serialisieren zu können (könnte durch int, byte, ulong ... unterstützt werden). Wird das so funktionieren, wie ich es möchte? Gibt es einen besseren Weg, es zu tun?Enum-Konvertierung/Serialisierung

public bool Serialize<TEnum>(ref TEnum data, TEnum min, TEnum max) where TEnum : struct, IComparable, IFormattable, IConvertible 
{ 
    if (!typeof(TEnum).IsEnum) 
    { 
     throw new ArgumentException("arguments must be an Enum"); 
    } 

    Type eType = Enum.GetUnderlyingType(data.GetType()); 

    if (eType == typeof(byte) || eType == typeof(ushort) || eType == typeof(uint) || eType == typeof(ulong)) 
    { 
     var data2 = (ulong) Convert.ChangeType(data, eType); 
     var min2 = (ulong) Convert.ChangeType(min, eType); 
     var max2 = (ulong) Convert.ChangeType(max, eType); 

     if (IsReading) 
     { 
      bool success = bs.Read(out data2, min2, max2); 
      data = (TEnum) Convert.ChangeType(data2, typeof(TEnum)); 
      return success; 
     } 
     bs.Write(data2, min2, max2); 
    } 
    else 
    { 
     var data2 = (long) Convert.ChangeType(data, eType); 
     var min2 = (long) Convert.ChangeType(min, eType); 
     var max2 = (long) Convert.ChangeType(max, eType); 

     if (IsReading) 
     { 
      bool success = bs.Read(out data2, min2, max2); 
      data = (TEnum) Convert.ChangeType(data2, typeof(TEnum)); 
      return success; 
     } 
     bs.Write(data2, min2, max2); 
    } 
    return true; 
} 
+1

Gibt es einen Grund, warum Sie nicht einen der eingebauten Serialisierer verwenden oder, wenn dies nicht funktioniert, etwas wie JSON.NET? –

+0

besser, wenn Code in separate Funktion, die Boolean zurückgeben wird und deklarieren alle Variablen oben auf der Funktion stattdessen in wenn und sonst, weil Sie redundante Sache tun, könnte es mir helfen, Sie auch diesen Code zu reinigen. und Sie können auch für Pakete von Drittanbietern versuchen Hoffe, es wird helfen Danke –

+0

@MatthewWatson gibt es einen Grund, aber es ist nicht wirklich relevant für die Frage. Ich versuche herauszufinden, generische Enum-Konvertierung. – Tim

Antwort

0

Um einen long oder ulong zu einem enum konvertieren, die durch eine kleinere Art von Integer gesichert ist, müssen Sie Enum.ToObject() verwenden. Convert.ChangeType() wird eine Ausnahme auslösen, wenn die zugrunde liegenden numerischen Typen nicht die gleiche Anzahl von Bytes haben. Und IConvertible.ToInt64() oder IConvertible.ToUInt64() wird etwas schneller sein als Convert.ChangeType(), da letztere tatsächlich die ehemalige bezeichnet.

Ansonsten sollte das folgende funktionieren und eine Enumeration als 8 Bytes in einem Serialisierungsstream serialisieren. Für eine Nicht-Enumeration ist dies weniger Platz sparend als die Serialisierung als zugrundeliegender numerischer Typ, hat aber den Vorteil, dass der darunterliegende numerische Typ nachträglich geändert werden kann (z. B. von int zu long, um weitere [Flags] Werte aufzunehmen) ohne ungültig zu machen alt Serialisierung Streams:

public static class SerializationExtensions 
{ 
    static bool EnumTypeIsSigned(this Type tEnum) 
    { 
     var underlyingType = Enum.GetUnderlyingType(tEnum); 
     if (underlyingType == typeof(long) || underlyingType == typeof(int) || underlyingType == typeof(short) || underlyingType == typeof(sbyte)) 
      return true; 
     if (underlyingType == typeof(ulong) || underlyingType == typeof(uint) || underlyingType == typeof(ushort) || underlyingType == typeof(byte)) 
      return false; 
     throw new ArgumentException(tEnum.Name + " is not an enum type"); 
    } 

    static bool IsSigned<TEnum>(this TEnum value) where TEnum : struct, IConvertible, IComparable, IFormattable 
    { 
     return typeof(TEnum).EnumTypeIsSigned(); 
    } 

    public static void WriteEnum<TEnum>(this BinaryWriter writer, TEnum value) where TEnum : struct, IConvertible, IComparable, IFormattable 
    { 
     if (value.IsSigned()) 
     { 
      var underlyingValue = checked(value.ToInt64(NumberFormatInfo.InvariantInfo)); 
      writer.Write(underlyingValue); 
     } 
     else 
     { 
      var underlyingValue = checked(value.ToUInt64(NumberFormatInfo.InvariantInfo)); 
      writer.Write(underlyingValue); 
     } 
    } 

    public static TEnum ReadEnum<TEnum>(this BinaryReader reader) where TEnum : struct, IConvertible, IComparable, IFormattable 
    { 
     if (typeof(TEnum).EnumTypeIsSigned()) 
     { 
      var underlyingValue = reader.ReadInt64(); 
      return checked((TEnum)Enum.ToObject(typeof(TEnum), underlyingValue)); 
     } 
     else 
     { 
      var underlyingValue = reader.ReadUInt64(); 
      return checked((TEnum)Enum.ToObject(typeof(TEnum), underlyingValue)); 
     } 
    } 
} 

Probe fiddle.