c# - 如何在 C# 中自定义反序列化包含自己字段的对象

标签 c# serialization deserialization abstract-class abstract-syntax-tree

以抽象语法树为例,二进制表达式有点像下面这样

class BinaryExpression : ExpressionSyntaxNode
{
    private ExpressionSyntaxNode left;
    private ExpressionSyntaxNode right;
    private Operator optr;
}

如果我想进行自定义序列化,根据https://msdn.microsoft.com/en-us/library/ms973893.aspx ,我需要实现 ISerialized 并拥有类似的东西

public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
{
    Left.GetObjectData(info, context);
    Right.GetObjectData(info, context);
    Optr.GetObjectData(info, context);
}

现在我很困惑我应该如何进行反序列化,因为它没有 SetObjectData 函数,而 otherwsie 可以允许我这样做

public virtual void SetObjectData(SerializationInfo info, StreamingContext context)
{
    Left = Left.SetObjectData(info, context);
    Right = Right.SetObjectData(info, context);
    Optr = Optr.SetObjectData(info, context);
}

而且我不知道特殊的构造函数在这种情况下如何提供帮助,因为我将这些字段(左、右和 optr)反序列化的确切类型在编译时是未知的。 ExpressionSynatxNode也只是一个抽象类,那么这种情况下的解决方案是什么。

最佳答案

您需要添加通过 SerializationInfo.AddValue() 将自身值添加到序列化流中,然后使用 GetValue() 取出反序列化的值:

[Serializable]
class BinaryExpression : ExpressionSyntaxNode, ISerializable
{
    private ExpressionSyntaxNode left;
    private ExpressionSyntaxNode right;
    private Operator optr;

    public BinaryExpression(ExpressionSyntaxNode left, ExpressionSyntaxNode right, Operator optr)
    {
        this.left = left;
        this.right = right;
        this.optr = optr;
    }

    #region ISerializable Members

    protected BinaryExpression(SerializationInfo info, StreamingContext context)
        : base(info, context)
    {
        left = (ExpressionSyntaxNode)info.GetValue("left", typeof(ExpressionSyntaxNode));
        right = (ExpressionSyntaxNode)info.GetValue("right", typeof(ExpressionSyntaxNode));
        optr = (Operator)info.GetValue("optr", typeof(Operator));
    }

    public override void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        base.GetObjectData(info, context);
        info.AddValue("left", left);
        info.AddValue("right", right);
        info.AddValue("optr", optr);
    }

    #endregion

    public override string ToString()
    {
        return string.Format("({0} {1} {2})", left.ToString(), optr.ToString(), right.ToString());
    }
}

为了扩展该示例,ExpressionSyntaxNode 类型的 ISerialized 对象的简单类层次结构可能如下所示。请注意流式构造函数的链接以及从派生类型到基类型对 GetObjectData() 的调用:

[Serializable]
abstract class ExpressionSyntaxNode : ISerializable
{
    protected ExpressionSyntaxNode()
    {
    }

    #region ISerializable Members

    protected ExpressionSyntaxNode(SerializationInfo info, StreamingContext context)
    {
    }

    public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
    {
    }

    #endregion
}

[Serializable]
abstract class ValueExpression<T> : ExpressionSyntaxNode, ISerializable where T : IConvertible
{
    T value;

    public T Value { get { return value; } }

    public ValueExpression(T value)
    {
        this.value = value;
    }

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

    protected ValueExpression(SerializationInfo info, StreamingContext context)
        : base(info, context)
    {
        this.value = (T)info.GetValue("value", typeof(T));
    }

    public override string ToString()
    {
        if (value == null)
            return "";
        return value.ToString();
    }
}

[Serializable]
class BooleanExpression : ValueExpression<bool>, ISerializable
{
    public BooleanExpression(bool value) : base(value) { }

    public override void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        base.GetObjectData(info, context);
    }

    protected BooleanExpression(SerializationInfo info, StreamingContext context)
        : base(info, context)
    {
    }
}

[Serializable]
public enum Operator
{
    And,
    Or
}

测试示例:

public class TestClass
{
    public static void Test()
    {
        var expression = new BinaryExpression(
            new BinaryExpression(new BooleanExpression(false), new BooleanExpression(true), Operator.And), 
            new BinaryExpression(new BooleanExpression(true), new BooleanExpression(false), Operator.Or), 
            Operator.Or);

        Debug.WriteLine("Initial expression: ");
        Debug.WriteLine(expression); // "((False And True) Or (True Or False))"

        if (expression.ToString() != "((False And True) Or (True Or False))")
            throw new InvalidOperationException();

        var binary = BinaryFormatterHelper.ToBinary(expression);

        var expression2 = BinaryFormatterHelper.FromBinary<BinaryExpression>(binary);

        Debug.WriteLine("Deserialized expression: ");
        Debug.WriteLine(expression2);

        if (expression.ToString() != expression2.ToString())
        {
            throw new InvalidOperationException();
        }
        else
        {
            Debug.WriteLine("Deserialized and original expressions are identical");
        }
    }
}

public static partial class BinaryFormatterHelper
{
    public static byte[] ToBinary<T>(T obj)
    {
        using (var stream = new MemoryStream())
        {
            new BinaryFormatter().Serialize(stream, obj);
            return stream.ToArray();
        }
    }

    public static T FromBinary<T>(byte[] data)
    {
        using (var stream = new MemoryStream(data))
        {
            var formatter = new BinaryFormatter();
            var obj = formatter.Deserialize(stream);
            if (obj is T)
                return (T)obj;
            return default(T);
        }
    }
}

关于c# - 如何在 C# 中自定义反序列化包含自己字段的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38313848/

相关文章:

java - 我可以在 Spring Boot 中为函数添加 "get"前缀吗

java - Jackson - 使用注释将第一个数组成员绑定(bind)到对象

c# - 我可以在属性中指定路径以将类中的属性映射到 JSON 中的子属性吗?

symfony - 将 json 反序列化为实体数组

c# - 用户 'IIS APPPOOL\myAppPoolName' 登录失败,无法为此添加新用户

c# - 应用程序代码中 try-catch block 无法捕获的异常

c# - XmlSerializer - 反序列化 SoapException 详细元素

c# - 通过 HTTP 调用 Azure Function 150 次导致异常

ios - 可靠地按顺序发送 AFNetworking 请求

java - 如何将多个对象写入可序列化文件并在程序再次使用时读取它们?