.NET, C#: How to add a custom serialization attribute that acts as ISerializable interface

狂风中的少年 提交于 2020-01-10 19:56:07

问题


I am doing some serialization of db linq objects, which contain EntitySet and EntityRef classes.

I found a pretty easy way to deal with serialization of these classes, by simply using ISerializable to properly handle members of this type (converting them to lists for serialization, and undoing it on deserialization).

However, it would be really nice if I could do:

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

Instead of:

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

Is there a way to do this? I looked through the serialization classes and couldn't seem to find any way to setup custom serialization filter routines (where I could look for my custom attribute).

Thanks!


回答1:


Yes, you can do this by implementing ISerializationSurrogate and ISurrogateSelector interfaces.

Something like this:

[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.Deserialize(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);
        }
    }
}



回答2:


Unfortunately no, ISerializable is an interface designed to allow you to control the serialization process while the SerializableAttribute is just a marker that says "this class can be serialized". However, you could look into something like PostSharp to add this functionality (take a look at the CompositionAspect).



来源:https://stackoverflow.com/questions/2174591/net-c-how-to-add-a-custom-serialization-attribute-that-acts-as-iserializable

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!