2016-09-09 5 views
0

Ich möchte anonyme Typvariable in Byte [] konvertieren, wie kann ich das tun?Serialisierung von anonymen Typen

Was ich versucht:

byte[] result; 

var my = new 
{ 
    Test = "a1", 
    Value = 0 
}; 

BinaryFormatter bf = new BinaryFormatter(); 

using (MemoryStream ms = new MemoryStream()) 
{ 
    bf.Serialize(ms, my); //-- ERROR 

    result = ms.ToArray(); 
} 

Ich habe Fehler:

An exception of type 'System.Runtime.Serialization.SerializationException' occurred in mscorlib.dll but was not handled in user code

Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]' in Assembly 'MyProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.Additional information: Type '<>f__AnonymousType10`2[[System.String, mscorlib,

Kann mir jemand helfen? Was mache ich falsch? Oder das ist nicht möglich?

+2

Was Sie "falsch machen", erwartet, dass anonyme Typen im Wesentlichen mit BinaryFormatter serialisierbar sind. Wie der Fehler sagt, ist der Typ nicht als serialisierbar gekennzeichnet - was mich nicht besonders überrascht. Ein anonymer Typ, der die Serialisierung unterstützt, würde erhebliche Probleme bereiten und würde sowieso nicht für nicht serialisierbare Eigenschaftstypen funktionieren. –

+0

Haben Sie überlegt, einen echten Typ zu verwenden und ihn als serialisierbar zu kennzeichnen? –

+0

Anonyme Typen wurden hinzugefügt, um LINQ einfacher zu unterstützen, damit keine benannten Typen für alles erstellt werden müssen. Sie sind nicht dazu gedacht, für langfristige Beharrlichkeit, Transport oder sogar für die Weitergabe in Ihrem Programm verwendet werden. Sie sind dazu bestimmt, lokal verwendet zu werden. Anonyme Typen sind daher nicht als serialisierbar gekennzeichnet.Da Sie die binäre Serialisierung später verwenden möchten, um sie zu deserialisieren, wäre es besser, wenn Sie uns sagen, was Sie in Bezug auf Funktionalität erreichen wollen, und dann können die Leute vielleicht eine bessere Antwort finden als "sorry, can ' t gemacht werden ". –

Antwort

1

Typen, die mit der Standard-Serialisiererfamilie (XmlSerializer, BinaryFormatter, DataContractSerializer, ...) serialisiert werden sollen, müssen als [Serializable] markiert sein, müssen öffentliche Typen sein und erfordern öffentliche Lese-/Schreibeigenschaften.

Anonyme Typen erfüllen diese Rolle nicht, da sie nicht über die erforderlichen Eigenschaften verfügen.

Erstellen Sie einfach einen Typ, der dies tut, und serialisieren Sie stattdessen.

1

Erstellen Sie einfach eine serializable Klasse

[Serializable] 
class myClass 
{ 
    public string Test { get; set; } 
    public int Value { get; set; } 
} 

Und Sie können Ihr Objekt die folgende Art und Weise serialisiert:

byte[] result; 
myClass my = new myClass() 
{ 
    Test = "a1", 
    Value = 0 
}; 
BinaryFormatter bf = new BinaryFormatter(); 
using (MemoryStream ms = new MemoryStream()) 
{ 
    bf.Serialize(ms, my); //NO MORE ERROR 
    result = ms.ToArray(); 
} 

Aber i'ts nicht möglich, einen anonymen Typ

+0

Vielen Dank, werde meine benutzerdefinierte Klasse verwenden Serializable – user3018896

+0

@ user3018896 groß, du bist willkommen – fubo

3

Erstens zu serialisiert: Der richtige Ansatz ist, wie bereits erwähnt, , um eine geeignete Klasse für die Serialisierung zu erstellen.

Es ist jedoch tatsächlich möglich, ein anonymes Objekt mit Json.Net zu serialisieren. Beachten Sie, dass ich nicht empfehle, dies tatsächlich in einem realen Projekt zu tun - es ist nur eine Kuriosität.

Dieser Code stützt sich auf eine hinterhältige Art und Weise von dem zugrunde liegenden Typ eines anonymen Objekt Zugriff durch ein exemplarisches Objekt als Typ Halter mit:

using System; 
using System.IO; 
using Newtonsoft.Json; 
using Newtonsoft.Json.Bson; 

public class Program 
{ 
    static void Main() 
    { 
     var data = serializeAnonymousObject(); 
     deserializeAnonymousObject(data); 
    } 

    static byte[] serializeAnonymousObject() 
    { 
     // This is in a separate method to demonstrate that you can 
     // serialize in one place and deserialize in another. 

     var my = new 
     { 
      Test = "a1", 
      Value = 12345 
     }; 

     return Serialize(my); 
    } 

    static void deserializeAnonymousObject(byte[] data) 
    { 
     // This is in a separate method to demonstrate that you can 
     // serialize in one place and deserialize in another. 

     var deserialized = new // Used as a type holder 
     { 
      Test = "", 
      Value = 0 
     }; 

     deserialized = Deserialize(deserialized, data); 

     Console.WriteLine(deserialized.Test); 
     Console.WriteLine(deserialized.Value); 
    } 

    public static byte[] Serialize(object obj) 
    { 
     using (var ms  = new MemoryStream()) 
     using (var writer = new BsonWriter(ms)) 
     { 
      new JsonSerializer().Serialize(writer, obj); 
      return ms.ToArray(); 
     } 
    } 

    public static T Deserialize<T>(T typeHolder, byte[] data) 
    { 
     using (var ms  = new MemoryStream(data)) 
     using (var reader = new BsonReader(ms)) 
     { 
      return new JsonSerializer().Deserialize<T>(reader); 
     } 
    } 
} 
+0

interessante Antwort, nicht sicher, wie Sie wissen, welche Mitglieder der anonyme Typ sollte ohne einen Vertrag, aber Sie gehen. – Jodrell

+0

@Jodrell In der Tat könnte man leicht falsch liegen, wenn man die anonymen Typen an den beiden Stellen, an denen sie verwendet werden, unterscheidet. Dies ist einer von vielen Gründen, warum dieser Ansatz nicht in realem Code verwendet werden sollte. –

0

Sie können aber nur, wenn Sie verrückt sind. Benutze das nicht. Das war mehr ein lustiges Problem.

class Program 
    { 
     static void Main(string[] args) 
     { 
      var obj1 = new 
      { 
       Test = "a1", 
       SubObject = new 
       { 
        Id = 1 
       }, 
       SubArray = new[] { new { Id = 1 }, new { Id = 2 } }, 
       Value = 0 
      }; 

      var my = new AnonymousSerializer(obj1); 
      BinaryFormatter bf = new BinaryFormatter(); 

      byte[] data; 
      using (MemoryStream ms = new MemoryStream()) 
      { 
       bf.Serialize(ms, my); 
       ms.Close(); 
       data = ms.ToArray(); 
      } 

      using (MemoryStream ms = new MemoryStream(data)) 
      { 
       var a = bf.Deserialize(ms) as AnonymousSerializer; 

       var obj2 = a.GetValue(obj1); 

       Console.WriteLine(obj1 == obj2); 

      } 
      Console.ReadLine(); 
     } 

     [Serializable] 
     public class AnonymousSerializer : ISerializable 
     { 
      private object[] properties; 

      public AnonymousSerializer(object objectToSerializer) 
      { 
       Type type = objectToSerializer.GetType(); 
       properties = type.GetProperties().Select(p => 
       { 
        if (p.PropertyType.IsArray && IsAnonymousType(p.PropertyType.GetElementType())) 
        { 
         var value = p.GetValue(objectToSerializer) as IEnumerable; 
         return value.Cast<object>().Select(obj => new AnonymousSerializer(obj)).ToArray() ; 
        }else if (IsAnonymousType(p.PropertyType)) 
        { 
         var value = p.GetValue(objectToSerializer); 
         return new AnonymousSerializer(value); 
        }else{ 
         return p.GetValue(objectToSerializer); 
        } 
       }).ToArray(); 
      } 

      public AnonymousSerializer(SerializationInfo info, StreamingContext context) 
      { 
       properties = info.GetValue("properties", typeof(object[])) as object[]; 
      } 


      public void GetObjectData(SerializationInfo info, StreamingContext context) 
      { 
       info.AddValue("properties", properties); 
      } 

      public T GetValue<T>(T prototype) 
      { 
       return GetValue(typeof(T)); 
      } 

      public dynamic GetValue(Type type) 
      { 
       Expression<Func<object>> exp = Expression.Lambda<Func<object>>(Creator(type)); 
       return exp.Compile()(); 
      } 

      private Expression Creator(Type type) 
      { 
       List<Expression> param = new List<Expression>(); 

       for (int i = 0; i < type.GetConstructors().First().GetParameters().Length; i++) 
       { 
        var cParam = type.GetConstructors().First().GetParameters()[i]; 
        if (cParam.ParameterType.IsArray && IsAnonymousType(cParam.ParameterType.GetElementType())) 
        { 
         var items = properties[i] as AnonymousSerializer[]; 
         var itemType = cParam.ParameterType.GetElementType(); 
         var data = items.Select(aser => aser.Creator(itemType)).ToArray(); 
         param.Add(Expression.NewArrayInit(itemType, data)); 
        } 
        else if (IsAnonymousType(cParam.ParameterType)) 
        { 
         param.Add((properties[i] as AnonymousSerializer).Creator(cParam.ParameterType)); 
        } 
        else 
        { 
         param.Add(Expression.Constant(properties[i])); 
        } 
       } 

       return Expression.New(type.GetConstructors().First(), param); 
      } 

      private static bool IsAnonymousType(Type type) 
      { 
       bool hasCompilerGeneratedAttribute = type.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Count() > 0; 
       bool nameContainsAnonymousType = type.FullName.Contains("AnonymousType"); 
       bool isAnonymousType = hasCompilerGeneratedAttribute && nameContainsAnonymousType; 

       return isAnonymousType; 
      } 
     } 
    } 
} 
0

Ähnlich wie bei früheren Antworten verwende ich JSON.NET hack;

Ich verwende dynamische Objekte meine Protokollierungszwecke, und es funktioniert sehr gut, da ich kein Schema dafür brauche.

Verwandte Themen