2010-02-01 9 views
5

Ich mache eine Serialisierung von db linq-Objekten, die EntitySet- und EntityRef-Klassen enthalten..NET, C#: So fügen Sie ein benutzerdefiniertes Serialisierungsattribut hinzu, das als ISerializable-Schnittstelle fungiert

Ich habe einen ziemlich einfachen Weg gefunden, mit der Serialisierung dieser Klassen umzugehen, indem ich einfach ISerializable benutzt, um Member dieses Typs korrekt zu bearbeiten (sie in Serialisierungslisten umzuwandeln und bei der Deserialisierung rückgängig zu machen).

Allerdings wäre es wirklich schön, wenn ich tun kann:

[Serializable] 
[SerializeLinqEntities] 
partial class Person 
{ ... } 

Statt:

partial class Person : ISerializable 
{ 
    public virtual void GetObjectData(SerializationInfo si, StreamingContext ctxt) 
    { 
    EntitySerializer.Serialize(this, typeof(Person), si, ctxt); 
    } 

    protected Person(SerializationInfo si, StreamingContext ctxt) 
    { 
    EntitySerializer.Deerialize(this, typeof(Person), si, ctxt); 
    } 
} 

Gibt es eine Möglichkeit, dies zu tun? Ich habe die Serialisierungsklassen durchgesehen und konnte keine Möglichkeit finden, benutzerdefinierte Serialisierungsfilterroutinen einzurichten (in denen ich nach meinen benutzerdefinierten Attributen suchen konnte).

Danke!

+0

Sieht aus wie IClientFormatterSinkProvider und IServerFormatterSinkProvider wird mir erlauben, einen BinaryFormatter mit Satz meine Gewohnheit SurrogateSelector zu liefern. Danke nochmal Sergey! – marq

+0

Hmm ... also, wie sich herausstellt, hat Microsoft das viel schwieriger gemacht, als es aussieht. Siehe den folgenden Link: http://www.123aspx.com/Rotor/RotorSrc.aspx?rot=40027 Sink-Provider, wie sich herausstellt, sind ziemlich komplex, und es ist nicht so einfach, nur eine zu implementieren. Ich wünschte wirklich, sie hätten bessere Interface-APIs zur Verfügung gestellt, um mit der binären Serialisierung zu interagieren ... – marq

Antwort

7

Ja, Sie können dies tun, indem Sie die Schnittstellen ISerializationSurrogate und ISurrogateSelector implementieren.

Etwas wie folgt aus:

[AttributeUsage(AttributeTargets.Class)] 
public class SerializeLinqEntities : Attribute 
{ 
} 

public class LinqEntitiesSurrogate : ISerializationSurrogate 
{ 
    public void GetObjectData(
     object obj, SerializationInfo info, StreamingContext context) 
    { 
     EntitySerializer.Serialize(this, obj.GetType(), info, context); 
    } 

    public object SetObjectData(
     object obj, SerializationInfo info, 
     StreamingContext context, ISurrogateSelector selector) 
    { 
     EntitySerializer.Deerialize(obj, obj.GetType(), info, context); 
     return obj; 
    } 
} 


/// <summary> 
/// Returns LinqEntitySurrogate for all types marked SerializeLinqEntities 
/// </summary> 
public class NonSerializableSurrogateSelector : ISurrogateSelector 
{ 
    public void ChainSelector(ISurrogateSelector selector) 
    { 
     throw new NotImplementedException(); 
    } 

    public ISurrogateSelector GetNextSelector() 
    { 
     throw new NotImplementedException(); 
    } 

    public ISerializationSurrogate GetSurrogate(
     Type type, StreamingContext context, out ISurrogateSelector selector) 
    { 
     if (!type.IsDefined(typeof(SerializeLinqEntities), false)) 
     { 
      //type not marked SerializeLinqEntities 
      selector = null; 
      return null; 
     } 
     selector = this; 
     return new LinqEntitiesSurrogate(); 
    } 

} 

[SerializeLinqEntities] 
public class TestSurrogate 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

class Program 
{ 
    static void Main(string[] str) 
    { 

     var ns1 = new TestSurrogate {Id = 47, Name = "TestName"}; 
     var formatter = new BinaryFormatter(); 
     formatter.SurrogateSelector = new NonSerializableSurrogateSelector(); 

     using (var ms = new MemoryStream()) 
     { 
      formatter.Serialize(ms, ns1); 
      ms.Position = 0; 

      var ns2 = (TestSurrogate) formatter.Deserialize(ms); 
      // Check serialization 
      Debug.Assert(ns1.Id == ns2.Id); 
      Debug.Assert(ns1.Name == ns2.Name); 
     } 
    } 
} 
+0

Das ist genau das, was ich will (ISurrogateSelector ist genau das, wonach ich gesucht habe). Also, letzte Frage - gibt es eine Möglichkeit, dies mit der automatisierten Serialisierung zu verwenden? Meine Serialisierung erfolgt über einen RPC-Aufruf (mit einem MarshalByRefObject). – marq

+0

+1 Ich dachte nicht einmal an 'ISerializationSurrogate', weil die Frage explizit Attribute erwähnt. Das einzige Problem mit dieser Lösung tritt auf, wenn Sie keinen Zugriff auf die Formatierungsinstanz haben, um die Eigenschaft 'SurrogateSelector' festzulegen. – Rory

+0

In WCF können Sie Surrogate leicht verwenden (http://msdn.microsoft.com/en-us/library/ms733064.aspx). Ich verwende keine Surrogate mit .net Remoting. Vielleicht hilft Ihnen Custom Sinks (http://www.codeproject.com/KB/IP/customsinks.aspx). –

0

Leider keine, ISerializable ist eine Schnittstelle entwickelt, um Ihnen zu ermöglichen, den Serialisierungsprozess zu steuern, während SerializableAttribute nur eine Markierung ist, die besagt "diese Klasse kann serialisiert werden". Sie könnten jedoch in etwas wie PostSharp suchen, um diese Funktionalität hinzuzufügen (werfen Sie einen Blick auf die CompositionAspect).