Anstatt SetObjectData()
und GetObjectData()
auf den Werten der Felder in Ihrem ISerializable
Typ aufrufen, müssen Sie die Werte selbst zum Serialisierungsstream über SerializationInfo.AddValue()
hinzufügen möchten, dann holen die deserialisiert Werte aus mit 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());
}
}
Um das Beispiel zu erweitern, könnte eine einfache Klassenhierarchie von ISerializable
Objekten vom Typ ExpressionSyntaxNode
wie folgt aussehen. Beachten Sie die Verkettung von Streaming-Konstrukteuren und ruft GetObjectData()
zur Basistyp abgeleitet:
[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
}
Testbeispiel:
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);
}
}
}
auf Ihrer Antwort das bedeutet ich habe keine Möglichkeit, den Konstruktor zu verwenden, die deserialisieren BinaryExpression obj? – user1935724
@ user1935724 - Ja, es ist nicht so gedacht. Der Serializer selbst ruft den Konstruktor auf und übergibt eine "SerializationInfo", die mit den Feldwerten für dieses bestimmte Objekt gefüllt ist und aus dem Serialisierungsstrom extrahiert wird. Da die verschachtelten Objekte intern natürlich unterschiedliche Feldwerte enthalten, ist beim Deserialisieren eine andere "SerializationInfo" erforderlich. – dbc