2 // System.Runtime.Serialization.SerializationTest.cs
4 // Author: Lluis Sanchez Gual (lluis@ximian.com)
10 using System.Diagnostics;
12 using System.Runtime.Serialization;
13 using System.Runtime.Serialization.Formatters.Binary;
14 using System.Reflection;
15 using System.Runtime.Remoting;
16 using System.Runtime.Remoting.Channels;
17 using System.Runtime.Remoting.Proxies;
18 using System.Runtime.Remoting.Messaging;
19 using System.Collections;
20 using NUnit.Framework;
23 namespace MonoTests.System.Runtime.Serialization
26 public class SerializationTest
33 public void TestSerialization ()
35 MethodTester mt = new MethodTester();
36 RemotingServices.Marshal (mt);
37 uri = RemotingServices.GetObjectUri (mt);
42 RemotingServices.Disconnect (mt);
46 #if !MONOTOUCH && !MOBILE_STATIC
48 public void DelegateSerializationTest ()
50 var a = new DelegateSerialization ();
53 var d2 = Delegate.CreateDelegate (typeof(Func<StringBuilder, int>), "val", typeof(SerializationTest).GetMethod ("HandleE2"));
54 a.E += (Func<StringBuilder, int>) d2;
56 using (var ms = new MemoryStream ()) {
57 var fmt = new BinaryFormatter ();
58 fmt.Serialize (ms, a);
61 ms.Seek (0, SeekOrigin.Begin);
62 var a2 = (DelegateSerialization) fmt.Deserialize (ms);
68 static int HandleE1 (StringBuilder arg)
74 public static int HandleE2 (object o, StringBuilder arg)
84 StreamingContext context = new StreamingContext (StreamingContextStates.Other);
85 SurrogateSelector sel = new SurrogateSelector();
86 sel.AddSurrogate (typeof (Point), context, new PointSurrogate());
87 sel.AddSurrogate (typeof (FalseISerializable), context, new FalseISerializableSurrogate());
89 List list = CreateTestData();
90 BinderTester_A bta = CreateBinderTestData();
92 ms = new MemoryStream();
93 BinaryFormatter f = new BinaryFormatter (sel, new StreamingContext(StreamingContextStates.Other));
94 f.Serialize (ms, list);
95 ProcessMessages (ms, null);
96 f.Serialize (ms, bta);
103 StreamingContext context = new StreamingContext (StreamingContextStates.Other);
104 SurrogateSelector sel = new SurrogateSelector();
105 sel.AddSurrogate (typeof (Point), context, new PointSurrogate());
106 sel.AddSurrogate (typeof (FalseISerializable), context, new FalseISerializableSurrogate());
108 BinaryFormatter f = new BinaryFormatter (sel, context);
110 object list = f.Deserialize (ms);
112 object[][] originalMsgData = null;
113 IMessage[] calls = null;
114 IMessage[] resps = null;
116 originalMsgData = ProcessMessages (null, null);
118 calls = new IMessage[originalMsgData.Length];
119 resps = new IMessage[originalMsgData.Length];
122 for (int n=0; n<originalMsgData.Length; n++)
124 calls[n] = (IMessage) f.Deserialize (ms);
125 resps[n] = (IMessage) f.DeserializeMethodResponse (ms, null, (IMethodCallMessage)calls[n]);
128 f.Binder = new TestBinder ();
129 object btbob = f.Deserialize (ms);
133 List expected = CreateTestData ();
134 List actual = (List) list;
135 expected.CheckEquals (actual, "List");
137 for (int i = 0; i < actual.children.Length - 1; ++i)
138 if (actual.children [i].next != actual.children [i+1])
139 Assert.Fail ("Deserialization did not restore pointer graph");
141 BinderTester_A bta = CreateBinderTestData();
142 Assert.AreEqual (btbob.GetType(), typeof (BinderTester_B), "BinderTest.class");
143 BinderTester_B btb = btbob as BinderTester_B;
146 Assert.AreEqual (btb.x, bta.x, "BinderTest.x");
147 Assert.AreEqual (btb.y, bta.y, "BinderTest.y");
150 CheckMessages ("MethodCall", originalMsgData, ProcessMessages (null, calls));
151 CheckMessages ("MethodResponse", originalMsgData, ProcessMessages (null, resps));
154 BinderTester_A CreateBinderTestData ()
156 BinderTester_A bta = new BinderTester_A();
158 bta.y = "binder tester";
162 List CreateTestData()
164 List list = new List();
165 list.name = "my list";
166 list.values = new SomeValues();
169 ListItem item1 = new ListItem();
170 ListItem item2 = new ListItem();
171 ListItem item3 = new ListItem();
173 item1.label = "value label 1";
175 item1.value.color = 111;
176 item1.value.point = new Point();
177 item1.value.point.x = 11;
178 item1.value.point.y = 22;
180 item2.label = "value label 2";
182 item2.value.color = 222;
184 item2.value.point = new Point();
185 item2.value.point.x = 33;
186 item2.value.point.y = 44;
188 item3.label = "value label 3";
189 item3.value.color = 333;
190 item3.value.point = new Point();
191 item3.value.point.x = 55;
192 item3.value.point.y = 66;
194 list.children = new ListItem[3];
196 list.children[0] = item1;
197 list.children[1] = item2;
198 list.children[2] = item3;
204 object[][] ProcessMessages (Stream stream, IMessage[] messages)
206 object[][] results = new object[9][];
208 AuxProxy prx = new AuxProxy (stream, uri);
209 MethodTester mt = (MethodTester)prx.GetTransparentProxy();
212 if (messages != null) prx.SetTestMessage (messages[0]);
213 res = mt.OverloadedMethod();
214 results[0] = new object[] {res};
216 if (messages != null) prx.SetTestMessage (messages[1]);
217 res = mt.OverloadedMethod(22);
218 results[1] = new object[] {res};
220 if (messages != null) prx.SetTestMessage (messages[2]);
221 int[] par1 = new int[] {1,2,3};
222 res = mt.OverloadedMethod(par1);
223 results[2] = new object[] { res, par1 };
225 if (messages != null) prx.SetTestMessage (messages[3]);
228 if (messages != null) prx.SetTestMessage (messages[4]);
229 res = mt.Simple ("hello",44);
230 results[4] = new object[] { res };
232 if (messages != null) prx.SetTestMessage (messages[5]);
233 res = mt.Simple2 ('F');
234 results[5] = new object[] { res };
236 if (messages != null) prx.SetTestMessage (messages[6]);
237 char[] par2 = new char[] { 'G' };
238 res = mt.Simple3 (par2);
239 results[6] = new object[] { res, par2 };
241 if (messages != null) prx.SetTestMessage (messages[7]);
242 res = mt.Simple3 (null);
243 results[7] = new object[] { res };
245 if (messages != null) prx.SetTestMessage (messages[8]);
247 SimpleClass b = new SimpleClass ('H');
248 res = mt.SomeMethod (123456, b);
249 results[8] = new object[] { res, b };
254 void CheckMessages (string label, object[][] original, object[][] serialized)
256 for (int n=0; n<original.Length; n++)
257 EqualsArray (label + " " + n, original[n], serialized[n]);
260 public static void AssertEquals(string message, Object expected, Object actual)
262 if (expected != null && expected.GetType().IsArray)
263 EqualsArray (message, (Array)expected, (Array)actual);
265 Assert.AreEqual (expected, actual, message);
268 public static void EqualsArray (string message, object oar1, object oar2)
270 if (oar1 == null || oar2 == null || !(oar1 is Array) || !(oar2 is Array))
272 Assert.AreEqual (oar1, oar2, message);
276 Array ar1 = (Array) oar1;
277 Array ar2 = (Array) oar2;
279 Assert.AreEqual (ar1.Length, ar2.Length, message + ".Length");
281 for (int n=0; n<ar1.Length; n++)
283 object av1 = ar1.GetValue(n);
284 object av2 = ar2.GetValue(n);
285 SerializationTest.AssertEquals (message + "[" + n + "]", av1, av2);
292 class PointSurrogate: ISerializationSurrogate
294 public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
296 Point p = (Point) obj;
297 info.AddValue ("xv",p.x);
298 info.AddValue ("yv",p.y);
301 public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
303 typeof (Point).GetField ("x").SetValue (obj, info.GetInt32 ("xv"));
304 typeof (Point).GetField ("y").SetValue (obj, info.GetInt32 ("yv"));
312 public string name = null;
313 public ListItem[] children = null;
314 public SomeValues values;
316 public void CheckEquals (List val, string context)
318 Assert.AreEqual (name, val.name, context + ".name");
319 values.CheckEquals (val.values, context + ".values");
321 Assert.AreEqual (children.Length, val.children.Length, context + ".children.Length");
323 for (int n=0; n<children.Length; n++)
324 children[n].CheckEquals (val.children[n], context + ".children[" + n + "]");
329 public class ListItem: ISerializable
335 ListItem (SerializationInfo info, StreamingContext ctx)
337 next = (ListItem)info.GetValue ("next", typeof (ListItem));
338 value = (ListValue)info.GetValue ("value", typeof (ListValue));
339 label = info.GetString ("label");
342 public void GetObjectData (SerializationInfo info, StreamingContext ctx)
344 info.AddValue ("next", next);
345 info.AddValue ("value", value);
346 info.AddValue ("label", label);
349 public void CheckEquals (ListItem val, string context)
351 Assert.AreEqual (label, val.label, context + ".label");
352 value.CheckEquals (val.value, context + ".value");
355 Assert.IsNull (val.next, context + ".next == null");
357 Assert.IsNotNull (val.next, context + ".next != null");
358 next.CheckEquals (val.next, context + ".next");
362 public override bool Equals(object obj)
364 ListItem val = (ListItem)obj;
365 if ((next == null || val.next == null) && (next != val.next)) return false;
366 if (next == null) return true;
367 if (!next.Equals(val.next)) return false;
368 return value.Equals (val.value) && label == val.label;
371 public override int GetHashCode ()
373 return base.GetHashCode ();
376 public ListItem next;
377 public ListValue value;
382 public struct ListValue
387 public override bool Equals(object obj)
389 ListValue val = (ListValue)obj;
390 return (color == val.color && point.Equals(val.point));
393 public void CheckEquals (ListValue val, string context)
395 Assert.AreEqual (color, val.color, context + ".color");
396 point.CheckEquals (val.point, context + ".point");
399 public override int GetHashCode ()
401 return base.GetHashCode ();
410 public override bool Equals(object obj)
412 Point p = (Point)obj;
413 return (x == p.x && y == p.y);
416 public void CheckEquals (Point p, string context)
418 Assert.AreEqual (x, p.x, context + ".x");
419 Assert.AreEqual (y, p.y, context + ".y");
422 public override int GetHashCode ()
424 return base.GetHashCode ();
429 public class FalseISerializable : ISerializable
433 public FalseISerializable (int n)
438 public void GetObjectData(SerializationInfo info, StreamingContext context)
440 throw new InvalidOperationException ("Serialize:We should not pass here.");
443 public FalseISerializable (SerializationInfo info, StreamingContext context)
445 throw new InvalidOperationException ("Deserialize:We should not pass here.");
449 public class FalseISerializableSurrogate : ISerializationSurrogate
451 public void GetObjectData (object obj, SerializationInfo info, StreamingContext context)
453 info.AddValue("field", Convert.ToString (((FalseISerializable)obj).field));
456 public object SetObjectData (object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
458 ((FalseISerializable)obj).field = Convert.ToInt32 (info.GetValue("field", typeof(string)));
464 public class SimpleClass
466 public SimpleClass (char v) { val = v; }
468 public override bool Equals(object obj)
470 if (obj == null) return false;
471 return val == ((SimpleClass)obj).val;
474 public override int GetHashCode()
476 return val.GetHashCode();
479 public int SampleCall (string str, SomeValues sv, ref int acum)
488 enum IntEnum { aaa, bbb, ccc }
489 enum ByteEnum: byte { aaa=221, bbb=3, ccc=44 }
491 delegate int SampleDelegate (string str, SomeValues sv, ref int acum);
494 public class SomeValues
522 public int[,,] _intsMulti;
524 SimpleClass[] _simples;
525 SimpleClass[,] _simplesMulti;
526 SimpleClass[][] _simplesJagged;
528 object[] _almostEmpty;
530 object[] _emptyObjectArray;
531 Type[] _emptyTypeArray;
532 SimpleClass[] _emptySimpleArray;
533 int[] _emptyIntArray;
534 string[] _emptyStringArray;
535 Point[] _emptyPointArray;
538 SampleDelegate _sampleDelegate;
539 SampleDelegate _sampleDelegate2;
540 SampleDelegate _sampleDelegate3;
541 SampleDelegate _sampleDelegateStatic;
542 SampleDelegate _sampleDelegateCombined;
544 SimpleClass _shared1;
545 SimpleClass _shared2;
546 SimpleClass _shared3;
548 FalseISerializable _falseSerializable;
552 _type = typeof (string);
553 _type2 = typeof (SomeValues);
554 _dbnull = DBNull.Value;
555 _assembly = typeof (SomeValues).Assembly;
556 _intEnum = IntEnum.bbb;
557 _byteEnum = ByteEnum.ccc;
562 _dateTime = new DateTime (1972,7,13,1,20,59);
563 _decimal = (decimal)101010.10101;
564 _double = 123456.6789;
569 _float = (float)654321.321;
574 Point p = new Point();
576 object boxedPoint = p;
579 object boxedLong = i;
581 _objects = new object[] { "string", (int)1234, null , /*boxedPoint, boxedPoint,*/ boxedLong, boxedLong};
582 _strings = new string[] { "an", "array", "of", "strings","I","repeat","an", "array", "of", "strings" };
583 _ints = new int[] { 4,5,6,7,8 };
584 _intsMulti = new int[2,3,4] { { {1,2,3,4},{5,6,7,8},{9,10,11,12}}, { {13,14,15,16},{17,18,19,20},{21,22,23,24} } };
585 _intsJagged = new int[2][] { new int[3] {1,2,3}, new int[2] {4,5} };
586 _simples = new SimpleClass[] { new SimpleClass('a'),new SimpleClass('b'),new SimpleClass('c') };
587 _simplesMulti = new SimpleClass[2,3] {{new SimpleClass('d'),new SimpleClass('e'),new SimpleClass('f')}, {new SimpleClass('g'),new SimpleClass('j'),new SimpleClass('h')}};
588 _simplesJagged = new SimpleClass[2][] { new SimpleClass[1] { new SimpleClass('i') }, new SimpleClass[2] {null, new SimpleClass('k')}};
589 _almostEmpty = new object[2000];
590 _almostEmpty[1000] = 4;
592 _emptyObjectArray = new object[0];
593 _emptyTypeArray = new Type[0];
594 _emptySimpleArray = new SimpleClass[0];
595 _emptyIntArray = new int[0];
596 _emptyStringArray = new string[0];
597 _emptyPointArray = new Point[0];
599 _doubles = new double[] { 1010101.101010, 292929.29292, 3838383.38383, 4747474.474, 56565.5656565, 0, Double.NaN, Double.MaxValue, Double.MinValue, Double.NegativeInfinity, Double.PositiveInfinity };
601 _sampleDelegate = new SampleDelegate(SampleCall);
602 _sampleDelegate2 = new SampleDelegate(_simples[0].SampleCall);
603 _sampleDelegate3 = new SampleDelegate(new SimpleClass('x').SampleCall);
604 _sampleDelegateStatic = new SampleDelegate(SampleStaticCall);
605 _sampleDelegateCombined = (SampleDelegate)Delegate.Combine (new Delegate[] {_sampleDelegate, _sampleDelegate2, _sampleDelegate3, _sampleDelegateStatic });
607 // This is to test that references are correctly solved
608 _shared1 = new SimpleClass('A');
609 _shared2 = new SimpleClass('A');
612 _falseSerializable = new FalseISerializable (2);
615 public int SampleCall (string str, SomeValues sv, ref int acum)
621 public static int SampleStaticCall (string str, SomeValues sv, ref int acum)
627 public void CheckEquals (SomeValues obj, string context)
629 Assert.AreEqual (_type, obj._type, context + "._type");
630 Assert.AreEqual (_type2, obj._type2, context + "._type2");
631 Assert.AreEqual (_dbnull, obj._dbnull, context + "._dbnull");
632 Assert.AreEqual (_assembly, obj._assembly, context + "._assembly");
634 Assert.AreEqual (_intEnum, obj._intEnum, context + "._intEnum");
635 Assert.AreEqual (_byteEnum, obj._byteEnum, context + "._byteEnum");
636 Assert.AreEqual (_bool, obj._bool, context + "._bool");
637 Assert.AreEqual (_bool2, obj._bool2, context + "._bool2");
638 Assert.AreEqual (_byte, obj._byte, context + "._byte");
639 Assert.AreEqual (_char, obj._char, context + "._char");
640 Assert.AreEqual (_dateTime, obj._dateTime, context + "._dateTime");
641 Assert.AreEqual (_decimal, obj._decimal, context + "._decimal");
642 Assert.AreEqual (_double, obj._double, context + "._double");
643 Assert.AreEqual (_short, obj._short, context = "._short");
644 Assert.AreEqual (_int, obj._int, context + "._int");
645 Assert.AreEqual (_long, obj._long, context + "._long");
646 Assert.AreEqual (_sbyte, obj._sbyte, context + "._sbyte");
647 Assert.AreEqual (_float, obj._float, context + "._float");
648 Assert.AreEqual (_ushort, obj._ushort, context + "._ushort");
649 Assert.AreEqual (_uint, obj._uint, context + "._uint");
650 Assert.AreEqual (_ulong, obj._ulong, context + "._ulong");
652 SerializationTest.EqualsArray (context + "._objects", _objects, obj._objects);
653 SerializationTest.EqualsArray (context + "._strings", _strings, obj._strings);
654 SerializationTest.EqualsArray (context + "._doubles", _doubles, obj._doubles);
655 SerializationTest.EqualsArray (context + "._ints", _ints, obj._ints);
656 SerializationTest.EqualsArray (context + "._simples", _simples, obj._simples);
657 SerializationTest.EqualsArray (context + "._almostEmpty", _almostEmpty, obj._almostEmpty);
659 SerializationTest.EqualsArray (context + "._emptyObjectArray", _emptyObjectArray, obj._emptyObjectArray);
660 SerializationTest.EqualsArray (context + "._emptyTypeArray", _emptyTypeArray, obj._emptyTypeArray);
661 SerializationTest.EqualsArray (context + "._emptySimpleArray", _emptySimpleArray, obj._emptySimpleArray);
662 SerializationTest.EqualsArray (context + "._emptyIntArray", _emptyIntArray, obj._emptyIntArray);
663 SerializationTest.EqualsArray (context + "._emptyStringArray", _emptyStringArray, obj._emptyStringArray);
664 SerializationTest.EqualsArray (context + "._emptyPointArray", _emptyPointArray, obj._emptyPointArray);
666 for (int i=0; i<2; i++)
667 for (int j=0; j<3; j++)
668 for (int k=0; k<4; k++)
669 SerializationTest.AssertEquals("SomeValues._intsMulti[" + i + "," + j + "," + k + "]", _intsMulti[i,j,k], obj._intsMulti[i,j,k]);
671 for (int i=0; i<_intsJagged.Length; i++)
672 for (int j=0; j<_intsJagged[i].Length; j++)
673 SerializationTest.AssertEquals ("SomeValues._intsJagged[" + i + "][" + j + "]", _intsJagged[i][j], obj._intsJagged[i][j]);
675 for (int i=0; i<2; i++)
676 for (int j=0; j<3; j++)
677 SerializationTest.AssertEquals ("SomeValues._simplesMulti[" + i + "," + j + "]", _simplesMulti[i,j], obj._simplesMulti[i,j]);
679 for (int i=0; i<_simplesJagged.Length; i++)
680 SerializationTest.EqualsArray ("SomeValues._simplesJagged", _simplesJagged[i], obj._simplesJagged[i]);
683 SerializationTest.AssertEquals ("SomeValues._sampleDelegate", _sampleDelegate ("hi", this, ref acum), _int);
684 SerializationTest.AssertEquals ("SomeValues._sampleDelegate_bis", _sampleDelegate ("hi", this, ref acum), obj._sampleDelegate ("hi", this, ref acum));
686 SerializationTest.AssertEquals ("SomeValues._sampleDelegate2", _sampleDelegate2 ("hi", this, ref acum), (int)_simples[0].val);
687 SerializationTest.AssertEquals ("SomeValues._sampleDelegate2_bis", _sampleDelegate2 ("hi", this, ref acum), obj._sampleDelegate2 ("hi", this, ref acum));
689 SerializationTest.AssertEquals ("SomeValues._sampleDelegate3", _sampleDelegate3 ("hi", this, ref acum), (int)'x');
690 SerializationTest.AssertEquals ("SomeValues._sampleDelegate3_bis", _sampleDelegate3 ("hi", this, ref acum), obj._sampleDelegate3 ("hi", this, ref acum));
692 SerializationTest.AssertEquals ("SomeValues._sampleDelegateStatic", _sampleDelegateStatic ("hi", this, ref acum), 99);
693 SerializationTest.AssertEquals ("SomeValues._sampleDelegateStatic_bis", _sampleDelegateStatic ("hi", this, ref acum), obj._sampleDelegateStatic ("hi", this, ref acum));
697 _sampleDelegateCombined ("hi", this, ref acum1);
698 obj._sampleDelegateCombined ("hi", this, ref acum2);
700 SerializationTest.AssertEquals ("_sampleDelegateCombined", acum1, _int + (int)_simples[0].val + (int)'x' + 99);
701 SerializationTest.AssertEquals ("_sampleDelegateCombined_bis", acum1, acum2);
703 SerializationTest.AssertEquals ("SomeValues._shared1", _shared1, _shared2);
704 SerializationTest.AssertEquals ("SomeValues._shared1_bis", _shared1, _shared3);
707 SerializationTest.AssertEquals ("SomeValues._shared2", _shared2.val, 'A');
708 SerializationTest.AssertEquals ("SomeValues._shared3", _shared3.val, 'B');
710 SerializationTest.AssertEquals ("SomeValues._falseSerializable", _falseSerializable.field, 2);
714 class MethodTester : MarshalByRefObject
716 public int OverloadedMethod ()
721 public int OverloadedMethod (int a)
726 public int OverloadedMethod (int[] a)
731 public void NoReturn ()
734 public string Simple (string a, int b)
739 public SimpleClass Simple2 (char c)
741 return new SimpleClass(c);
744 public SimpleClass Simple3 (char[] c)
746 if (c != null) return new SimpleClass(c[0]);
750 public int SomeMethod (int a, SimpleClass b)
754 int r = a + c.Length;
762 class AuxProxy: RealProxy
764 public static bool useHeaders = false;
767 IMethodMessage _testMsg;
769 public AuxProxy(Stream stream, string uri): base(typeof(MethodTester))
775 public void SetTestMessage (IMessage msg)
777 _testMsg = (IMethodMessage)msg;
778 _testMsg.Properties["__Uri"] = _uri;
781 public override IMessage Invoke(IMessage msg)
783 IMethodCallMessage call = (IMethodCallMessage)msg;
784 if (call.MethodName.StartsWith ("Initialize")) return new ReturnMessage(null,null,0,null,(IMethodCallMessage)msg);
786 call.Properties["__Uri"] = _uri;
790 SerializeCall (call);
791 IMessage response = ChannelServices.SyncDispatchMessage (call);
792 SerializeResponse (response);
795 else if (_testMsg != null)
797 if (_testMsg is IMethodCallMessage)
798 return ChannelServices.SyncDispatchMessage (_testMsg);
803 return ChannelServices.SyncDispatchMessage (call);
806 void SerializeCall (IMessage call)
808 RemotingSurrogateSelector rss = new RemotingSurrogateSelector();
809 var fmt = new BinaryFormatter (rss, new StreamingContext(StreamingContextStates.Remoting));
810 fmt.Serialize (_stream, call, GetHeaders());
813 void SerializeResponse (IMessage resp)
815 RemotingSurrogateSelector rss = new RemotingSurrogateSelector();
816 var fmt = new BinaryFormatter (rss, new StreamingContext(StreamingContextStates.Remoting));
817 fmt.Serialize (_stream, resp, GetHeaders());
820 Header[] GetHeaders()
826 hs[0] = new Header("unom",new SimpleClass('R'));
832 public class TestBinder : SerializationBinder
834 public override Type BindToType (string assemblyName, string typeName)
836 if (typeName.IndexOf("BinderTester_A") != -1)
837 typeName = typeName.Replace ("BinderTester_A", "BinderTester_B");
839 return Assembly.Load (assemblyName).GetType (typeName);
844 public class BinderTester_A
851 public class BinderTester_B
858 class DelegateSerialization
860 public event Func<StringBuilder, int> E;
864 var sb = new StringBuilder ();
865 Assert.AreEqual (2, E (sb), "#1");
866 Assert.AreEqual ("E1E2|val", sb.ToString (), "#2");