2010-02-01 15 views
5

que estoy haciendo algunos serialización de objetos LINQ db, que contienen clases EntitySet y EntityRef..NET, C#: ¿Cómo añadir un atributo de serialización personalizado que actúa como interfaz ISerializable

Encontré una manera bastante fácil de manejar la serialización de estas clases, simplemente usando ISerializable para manejar adecuadamente los miembros de este tipo (convirtiéndolos en listas para la serialización, y deshaciendo la deserialización).

Sin embargo, sería muy bueno si pudiera hacer:

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

En lugar de:

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

¿Hay una manera de hacer esto? Miré a través de las clases de serialización y no parecía encontrar ninguna forma de configurar las rutinas de filtro de serialización personalizadas (donde podía buscar mi atributo personalizado).

Gracias!

+0

Parece que IClientFormatterSinkProvider y IServerFormatterSinkProvider me permitirá proporcionar una BinaryFormatter con mi conjunto SurrogateSelector personalizado. Gracias de nuevo, Sergey! – marq

+0

Hmm ... así que, como resultado, Microsoft ha hecho esto mucho más difícil de lo que parece. Vea el siguiente enlace: http://www.123aspx.com/Rotor/RotorSrc.aspx?rot=40027 Los proveedores de sumidero, como resultado, son bastante complejos, y no es tan simple como simplemente implementar uno. Realmente deseo que habían proporcionado una mejor interfaz de API para interactuar con la serialización binaria ... – marq

Respuesta

7

sí, se puede hacer esto mediante la implementación de ISerializationSurrogate y ISurrogateSelector interfaces.

Algo como esto:

[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

eso es exactamente lo que yo quiero (ISurrogateSelector es exactamente lo que estaba buscando). Entonces, pregunta final: ¿hay alguna manera de usar esto con la serialización automatizada? Mi serialización está sucediendo a través de una llamada RPC (usando un MarshalByRefObject). – marq

+0

1 ni siquiera pienso en 'ISerializationSurrogate' porque la pregunta menciona explícitamente atributos. El único problema con esta solución se produce cuando no tiene acceso a la instancia del formateador para establecer la propiedad 'SurrogateSelector'. – Rory

+0

En WCF puede utilizar simplemente sustitutos (http://msdn.microsoft.com/en-us/library/ms733064.aspx). No usé sustitutos con .net remoto. Tal vez Custom Sinks puede ayudarte (http://www.codeproject.com/KB/IP/customsinks.aspx). –

0

Desafortunadamente no, ISerializable es una interfaz diseñada para permitirle controlar el proceso de serialización mientras que el SerializableAttribute es solo un marcador que dice "esta clase se puede serializar". Sin embargo, usted podría mirar en algo así como PostSharp añadir esta funcionalidad (echar un vistazo a la CompositionAspect).

Cuestiones relacionadas