示例#1
0
        private static SerializerConfig GetConfig()
        {
            SerializerConfig config = new SerializerConfig();

            config.DefaultTargets = TargetMember.AllProperties;
            //config.ConfigType<MapState>().ConfigMember(ms => ms.TalkingNation).Exclude().ConstructBy(typeof(MapState).GetConstructors()[0]);
            config.ConfigType <Nation>().ConstructBy(typeof(Nation).GetConstructors()[0]);
            config.ConfigType <WarSide>().ConstructBy(typeof(WarSide).GetConstructors()[0]);
            config.ConfigType <PixelData>().ConstructBy(typeof(PixelData).GetConstructors()[0]);
            config.ConfigType <UnorderedBytePair>().ConstructBy(typeof(UnorderedBytePair).GetConstructors()[0]);

            return(config);
        }
示例#2
0
        public Ceras(bool forNetworking = true)
        {
            if (CerasBufferPool.Pool == null)
            {
                CerasBufferPool.Pool = new CerasDefaultBufferPool();
            }

            mSerializerConfig = new SerializerConfig
            {
                PreserveReferences = false
            };

            mSerializerConfig.Advanced.SealTypesWhenUsingKnownTypes = forNetworking;

            if (forNetworking)
            {
                mSerializerConfig.VersionTolerance.Mode = VersionToleranceMode.Disabled;
                mSerializerConfig.KnownTypes.AddRange(KnownTypes);
                mSerializerConfig.KnownTypes.ForEach(
                    knownType =>
                    mSerializerConfig.ConfigType(knownType).TypeConstruction = TypeConstruction.ByUninitialized()
                    );
            }
            else
            {
                mSerializerConfig.VersionTolerance.Mode = VersionToleranceMode.Standard;
            }

            mSerializer = new CerasSerializer(mSerializerConfig);
        }
示例#3
0
        static void CustomComparerFormatter()
        {
            // Our HashSet<byte> is losing its Comparer
            // We use a custom formatter to fix it

            SerializerConfig config = new SerializerConfig();

            config.OnResolveFormatter.Add((c, t) =>
            {
                if (t == typeof(HashSet <byte[]>))
                {
                    return(new HashSetFormatterThatKeepsItsComparer());
                }
                return(null);                // continue searching
            });

            config.ConfigType <HashSet <byte[]> >()
            .SetFormatter(new HashSetFormatterThatKeepsItsComparer());

            var ceras = new CerasSerializer(config);

            var set = new HashSet <byte[]>(new CustomComparer());

            set.Add(new byte[] { 1, 2, 3 });
            set.Add(new byte[] { 4, 5, 6 });

            var clone = ceras.Deserialize <HashSet <byte[]> >(ceras.Serialize(set));

            Debug.Assert(clone.Comparer.GetType() == typeof(CustomComparer));
        }
示例#4
0
        private void AddKnownTypes(SerializerConfig config, string nameSpce)
        {
            var packetTypes = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.Namespace == nameSpce).ToList();

            foreach (var typ in packetTypes)
            {
                config.KnownTypes.Add(typ);
                mSerializerConfig.ConfigType(typ).TypeConstruction = TypeConstruction.ByUninitialized();
            }
        }
示例#5
0
        public void CanNotConfigurePrimitives()
        {
            // Changing any settings for "Serialization Primitives" should not be allowed
            // String, Type, int, ...

            SerializerConfig config = new SerializerConfig();

            HashSet <Type> primitiveTypes = new HashSet <Type>
            {
                typeof(Type),
                typeof(byte),
                typeof(int),
                typeof(float),
                typeof(string),
            };

            bool configGotCalled = false;

            config.OnConfigNewType = t =>
            {
                if (primitiveTypes.Contains(t.Type))
                {
                    configGotCalled = true;
                }
            };

            // Configuring primitives should not be possible
            foreach (var t in primitiveTypes)
            {
                ExpectException(() => config.ConfigType(t));
            }

            // Enum is not a real type (it's an abstract base class)
            ExpectException(() => config.ConfigType(typeof(Enum)));


            if (configGotCalled)
            {
                throw new Exception("on config new type should not be called for 'serialization primitives'");
            }
        }
示例#6
0
        private void ReadData(byte[] buffer)
        {
            var config = new SerializerConfig();

            config.VersionTolerance.Mode = VersionToleranceMode.Standard;

            config.ConfigType <VersionTest>().CustomResolver = (c, t)
                                                               => new Ceras.Versioning.DynamicEmulator <VersionTest>(c, c.GetTypeMetaData(t).PrimarySchema);

            CerasSerializer ceras = new CerasSerializer(config);

            var clone = ceras.Deserialize <VersionTest>(buffer);
        }
示例#7
0
        public void CustomFormatterForEnum()
        {
            var config = new SerializerConfig();

            config.ConfigType <DayOfWeek>().CustomFormatter = new DayOfWeekFormatter();

            var ceras = new CerasSerializer(config);

            Assert.True(ceras.Deserialize <DayOfWeek>(ceras.Serialize(DayOfWeek.Sunday)) == DayOfWeek.Sunday);
            Assert.True(ceras.Deserialize <DayOfWeek>(ceras.Serialize(DayOfWeek.Monday)) == DayOfWeek.Monday);
            Assert.True(ceras.Deserialize <DayOfWeek>(ceras.Serialize(DayOfWeek.Saturday)) == DayOfWeek.Saturday);
            Assert.True(ceras.Deserialize <DayOfWeek>(ceras.Serialize((DayOfWeek)591835)) == (DayOfWeek)591835);
        }
示例#8
0
        public void WarnUserAgainstPropertyStruct()
        {
            Assert.Throws <WarningException>(() =>
            {
                var config = new SerializerConfig();
                config.VersionTolerance.Mode = VersionToleranceMode.Standard;

                var tc = config.ConfigType <PropertyStruct>();

                CerasSerializer ceras = new CerasSerializer(config);
                var obj           = new PropertyStruct();
                obj.DeviceAddress = 1235;
                obj.SwitchId      = 45454545;

                var data  = ceras.Serialize(obj);
                var clone = ceras.Deserialize <PropertyStruct>(data);
            });
        }
        public DeserializationImmutablePoco()
        {
            var config = new SerializerConfig {
                DefaultTargets = TargetMember.AllFields, PreserveReferences = false
            };

            config.Advanced.ReadonlyFieldHandling       = ReadonlyFieldHandling.ForcedOverwrite;
            config.Advanced.SkipCompilerGeneratedFields = false;
            config.ConfigType <ImmutablePoco>().ConstructByUninitialized();
            ceras = new CerasSerializer(config);

            for (int i = 0; i < 1000; ++i)
            {
                _t1.Add(new ImmutablePoco("hello", 123, Guid.NewGuid(), DateTime.Now));
            }

            //_hyperion.Serialize(_t1, _m2);
        }
示例#10
0
        public void DerivedProperties()
        {
            var config = new SerializerConfig();

            config.VersionTolerance.Mode = VersionToleranceMode.Standard;
            CerasSerializer ceras = new CerasSerializer(config);

            var obj = new DerivedClass();

            obj.Name = "derived!";

            var data  = ceras.Serialize(obj);
            var clone = ceras.Deserialize <DerivedClass>(data);

            Assert.True(clone.Name == obj.Name);

            Assert.True(config.ConfigType <DerivedClass>().Members.Count(m => m.Member is PropertyInfo) == 1);
        }
示例#11
0
        private static void TryConfig3(DateTime dt, Foo foo)
        {
            try
            {
                var cfg = new SerializerConfig()
                {
                    PreserveReferences = false
                };
                cfg.ConfigType <DateTime>()
                .ConfigField("dateData").Include();

                SerAndDeser(dt, foo, cfg);
            }
            catch (Ceras.Exceptions.WarningException ex)
            {
                throw ex; //Shouldn't be happening
            }
            catch (Exception ex)
            {
                throw ex; //Shouldn't be happening
            }
        }
示例#12
0
        void KnownColorFormatter()
        {
            SerializerConfig config = new SerializerConfig();

            config.ConfigType <Color>()
            .CustomFormatter = new ColorFormatter();

            var colors = new Color[]
            {
                Color.Azure,
                Color.FromArgb(255, 50, 150, 10),
                Color.FromArgb(255, 255, 255, 255),
                Color.White,
            };

            var ceras = new CerasSerializer(config);
            var clone = ceras.Deserialize <Color[]>(ceras.Serialize(colors));

            for (int i = 0; i < colors.Length; i++)
            {
                Assert.True(colors[i] == clone[i]);
                Assert.True(colors[i].Equals(clone[i]));
            }
        }
示例#13
0
        private static void TryConfig2(DateTime dt, Foo foo)
        {
            try
            {
                var cfg = new SerializerConfig()
                {
                    PreserveReferences = false
                };
                cfg.ConfigType <DateTime>()
                .CustomResolver = (c, t) => c.Advanced
                                  .GetFormatterResolver <Ceras.Resolvers.DynamicObjectFormatterResolver>()
                                  .GetFormatter(t);

                SerAndDeser(dt, foo, cfg);
            }
            catch (Ceras.Exceptions.WarningException ex)
            {
                throw ex; //Shouldn't be happening
            }
            catch (Exception ex)
            {
                throw ex; //Shouldn't be happening
            }
        }
示例#14
0
        public void TestDirectPoolingMethods()
        {
            var pool = new InstancePoolTest();

            // Test: Ctor with argument
            {
                SerializerConfig config = new SerializerConfig();

                config.ConfigType <Person>()
                // Select ctor, not delegate
                .ConstructBy(() => new Person("name"));

                var clone = DoRoundTripTest(config);
                Assert.True(clone != null);
                Assert.True(clone.Name.StartsWith("riki"));
                Assert.True(clone.Name.EndsWith(Person.CtorSuffix));
            }

            // Test: Manual config
            {
                SerializerConfig config = new SerializerConfig();

                config.ConfigType <Person>()
                .ConstructBy(TypeConstruction.ByStaticMethod(() => StaticPoolTest.CreatePerson()));

                var clone = DoRoundTripTest(config);
                Assert.True(clone != null);
            }

            // Test: Normal ctor, but explicitly
            {
                SerializerConfig config = new SerializerConfig();

                config.ConfigType <Person>()
                // Select ctor, not delegate
                .ConstructBy(() => new Person());

                var clone = DoRoundTripTest(config);
                Assert.True(clone != null);
            }

            // Test: Construct from instance-pool
            {
                SerializerConfig config = new SerializerConfig();

                config.ConfigType <Person>()
                // Instance + method select
                .ConstructBy(pool, () => pool.CreatePerson());

                var clone = DoRoundTripTest(config);
                Assert.True(clone != null);
                Assert.True(pool.IsFromPool(clone));
            }

            // Test: Construct from static-pool
            {
                SerializerConfig config = new SerializerConfig();

                config.ConfigType <Person>()
                // method select
                .ConstructBy(() => StaticPoolTest.CreatePerson());

                var clone = DoRoundTripTest(config);
                Assert.True(clone != null);
                Assert.True(StaticPoolTest.IsFromPool(clone));
            }

            // Test: Construct from any delegate (in this example: a lambda expression)
            {
                SerializerConfig config = new SerializerConfig();

                Person referenceCapturedByLambda = null;

                config.ConfigType <Person>()
                // Use delegate
                .ConstructByDelegate(() =>
                {
                    var obj = new Person();
                    referenceCapturedByLambda = obj;
                    return(obj);
                });

                var clone = DoRoundTripTest(config);
                Assert.True(clone != null);
                Assert.True(ReferenceEquals(clone, referenceCapturedByLambda));
            }

            // Test: Construct from instance-pool, with parameter
            {
                SerializerConfig config = new SerializerConfig();

                config.ConfigType <Person>()
                // Use instance + method selection
                .ConstructBy(pool, () => pool.CreatePersonWithName("abc"));

                var clone = DoRoundTripTest(config);
                Assert.True(clone != null);
                Assert.True(clone.Name.StartsWith("riki"));
                Assert.True(pool.IsFromPool(clone));
            }

            // Test: Construct from static-pool, with parameter
            {
                SerializerConfig config = new SerializerConfig();

                config.ConfigType <Person>()
                // Use instance + method selection
                .ConstructBy(() => StaticPoolTest.CreatePersonWithName("abc"));

                var clone = DoRoundTripTest(config);
                Assert.True(clone != null);
                Assert.True(clone.Name.StartsWith("riki"));
                Assert.True(StaticPoolTest.IsFromPool(clone));
            }
        }
示例#15
0
        public void Step3_Recycling()
        {
            /*
             * Scenario:
             *		- You might be developing a game or other timing-sensitive application
             *		  where performance is extremely important and where small stutters by the GC have to be avoided
             *		- You have your own object-pool and want Ceras to obtain instances from it and return them to it.
             *
             * What you want:
             *		- You want more performance
             *		- You want to decrease GC pauses and GC pressure
             *
             * What can we do:
             *		- Recycle objects, reducing GC pressure
             *		- Take objects from a pool instead of doing "new MyThing()" to improve cache-coherence.
             */



            // Assuming we're receiving "network packets" over the internet, we'd instantiate a new object every time we call Deserialize
            // That is pretty wasteful. We receive one object, deserialize it, use it, then discard it, ...
            //
            // What we can do is have one instance that we can just overwrite all the time!
            //
            // Ceras will use the provided object and overwrite the fields; instead of creating a new object instance.
            // If no instance is provided, Ceras will just instantiate one.
            //
            // Hint: This can also be used to quickly set or reset an object to some predefined values in other scenarios.

            var serializer = new CerasSerializer();

            Person recycledPerson = new Person {
                Health = 35, Name = "test"
            };

            byte[] buffer = serializer.Serialize(recycledPerson);             // Lets assume we already got a network buffer and now we just have to read it.

            for (int i = 0; i < 100; i++)
            {
                // No person object will be allocated, the fields
                // of 'recycledPerson' will just be overwritten
                serializer.Deserialize <Person>(ref recycledPerson, buffer);
            }



            //
            // Now we'll use some extremely simple object-pooling solution to reduce GC pressure.
            // The 'MyVerySimplePool' is obviously just for illustration, in something like Unity3D you would
            // of course make something much more elaborate...
            //
            // If the data in the buffer tells us "it's a 'null' object" then Ceras will of course set 'recycledPerson' to null.
            // But now you might wonder what happens to the instance that was previously inside 'recycledPerson'.
            // Normally the answer would be that the object would be simply lost (and eventually its space would be reclaimed by the .NET "garbage-collector").
            //
            // In some scenarios (games) we don't want this because garbage-collections often cause stutters.
            // A common solution to this is object-pooling.
            // Ceras supports that by allowing you to "catch" unused objects, so you can return them to your object-pool.

            MyVerySimplePool <Person> pool = new MyVerySimplePool <Person>();

            SerializerConfig config = new SerializerConfig();

            config.ConfigType <Person>()
            .ConstructBy(() => new Person())                       // select ctor
            .ConstructBy(pool, () => pool.GetFromPool());          // or create from a pool

            config.Advanced.DiscardObjectMethod = obj =>
            {
                pool.ReturnToPool((Person)obj);
            };


            serializer = new CerasSerializer(config);

            // todo: the example is not fully done yet

            /*
             * var personA = new Person { Name = "a", Health = 1 };
             * var personB = new Person { Name = "b", Health = 2 };
             * var personC = new Person { Name = "c", Health = 3 };
             *
             * personA.BestFriend = personB;
             * personB.BestFriend = personC;
             * personC.BestFriend = personA;
             *
             * serializer.Serialize();
             */
        }
示例#16
0
        static void ReadonlyTest()
        {
            // Test #1:
            // By default the setting is off. Fields are ignored.
            {
                SerializerConfig config = new SerializerConfig();
                CerasSerializer  ceras  = new CerasSerializer(config);

                ReadonlyFieldsTest obj = new ReadonlyFieldsTest(5, "xyz", new ReadonlyFieldsTest.ContainerThingA {
                    Setting1 = 10, Setting2 = "asdasdas"
                });

                var data = ceras.Serialize(obj);

                var cloneNew = ceras.Deserialize <ReadonlyFieldsTest>(data);

                Debug.Assert(cloneNew.Int == 1);
                Debug.Assert(cloneNew.String == "a");
                Debug.Assert(cloneNew.Container == null);
            }

            // Test #2A:
            // In the 'Members' mode we expect an exception for readonly value-typed fields.
            {
                SerializerConfig config = new SerializerConfig();
                config.Advanced.ReadonlyFieldHandling = ReadonlyFieldHandling.Members;

                config.ConfigType <ReadonlyFieldsTest>()
                .ConfigMember(f => f.Int).Include()
                .ConfigMember(f => f.String).Include();


                CerasSerializer ceras = new CerasSerializer(config);

                ReadonlyFieldsTest obj = new ReadonlyFieldsTest(5, "55555", new ReadonlyFieldsTest.ContainerThingA {
                    Setting1 = 555555, Setting2 = "555555555"
                });

                var data = ceras.Serialize(obj);

                ReadonlyFieldsTest existingTarget = new ReadonlyFieldsTest(6, "66666", null);

                bool gotException = false;
                try
                {
                    var cloneNew = ceras.Deserialize <ReadonlyFieldsTest>(data);
                }
                catch (Exception ex)
                {
                    gotException = true;
                }

                Debug.Assert(gotException);                 // We want an exception
            }

            // Test #2B:
            // In the 'Members' mode (when not dealing with value-types)
            // we want Ceras to re-use the already existing object
            {
                SerializerConfig config = new SerializerConfig();
                config.Advanced.ReadonlyFieldHandling = ReadonlyFieldHandling.Members;

                config.ConfigType <ReadonlyFieldsTest>()
                .ConfigMember(f => f.Int).Exclude()
                .ConfigMember(f => f.String).Exclude()
                .ConfigMember(f => f.Container).Include(ReadonlyFieldHandling.Members);

                CerasSerializer ceras = new CerasSerializer(config);

                ReadonlyFieldsTest obj = new ReadonlyFieldsTest(5, "55555", new ReadonlyFieldsTest.ContainerThingA {
                    Setting1 = 555555, Setting2 = "555555555"
                });

                var data = ceras.Serialize(obj);

                var newContainer = new ReadonlyFieldsTest.ContainerThingA {
                    Setting1 = -1, Setting2 = "this should get overwritten"
                };
                ReadonlyFieldsTest existingTarget = new ReadonlyFieldsTest(6, "66666", newContainer);

                // populate existing data
                ceras.Deserialize <ReadonlyFieldsTest>(ref existingTarget, data);

                // The simple fields should have been ignored
                Debug.Assert(existingTarget.Int == 6);
                Debug.Assert(existingTarget.String == "66666");

                // The reference itself should not have changed
                Debug.Assert(existingTarget.Container == newContainer);

                // The content of the container should be changed now
                Debug.Assert(newContainer.Setting1 == 555555);
                Debug.Assert(newContainer.Setting2 == "555555555");
            }


            // Test #3
            // In 'ForcedOverwrite' mode Ceras should fix all possible mismatches by force (reflection),
            // which means that it should work exactly like as if the field were not readonly.
            {
                SerializerConfig config = new SerializerConfig();
                config.Advanced.ReadonlyFieldHandling = ReadonlyFieldHandling.ForcedOverwrite;
                CerasSerializer ceras = new CerasSerializer(config);

                // This time we want Ceras to fix everything, reference mismatches and value mismatches alike.

                ReadonlyFieldsTest obj = new ReadonlyFieldsTest(5, "55555", new ReadonlyFieldsTest.ContainerThingA {
                    Setting1 = 324, Setting2 = "1134"
                });

                var data = ceras.Serialize(obj);

                ReadonlyFieldsTest existingTarget = new ReadonlyFieldsTest(123, null, new ReadonlyFieldsTest.ContainerThingB());

                // populate existing object
                ceras.Deserialize <ReadonlyFieldsTest>(ref existingTarget, data);


                // Now we really check for everything...

                // Sanity check, no way this could happen, but lets make sure.
                Debug.Assert(ReferenceEquals(obj, existingTarget) == false);

                // Fields should be like in the original
                Debug.Assert(existingTarget.Int == 5);
                Debug.Assert(existingTarget.String == "55555");

                // The container type was wrong, Ceras should have fixed that by instantiating a different object
                // and writing that into the readonly field.
                var container = existingTarget.Container as ReadonlyFieldsTest.ContainerThingA;
                Debug.Assert(container != null);

                // Contents of the container should be correct as well
                Debug.Assert(container.Setting1 == 324);
                Debug.Assert(container.Setting2 == "1134");
            }

            // Test #4:
            // Everything should work fine when using the MemberConfig attribute as well
            {
                var ceras = new CerasSerializer();

                var obj = new ReadonlyFieldsTest2();
                obj.Numbers.Clear();
                obj.Numbers.Add(234);

                var data = ceras.Serialize(obj);

                var clone        = new ReadonlyFieldsTest2();
                var originalList = clone.Numbers;
                ceras.Deserialize(ref clone, data);

                Debug.Assert(originalList == clone.Numbers);           // actual reference should not have changed
                Debug.Assert(clone.Numbers.Count == 1);                // amount of entries should have changed
                Debug.Assert(clone.Numbers[0] == 234);                 // entry itself should be right
            }

            // todo: also test the case where the existing object does not match the expected type
        }
示例#17
0
        public void Step1_SimpleUsage()
        {
            //
            // 1.) Simple usage
            // aka. "I'm here for the cool features! I want to optimize for max-performance later"
            var person = new Person {
                Name = "riki", Health = 100
            };

            var ceras = new CerasSerializer();

            var data = ceras.Serialize(person);

            data.VisualizePrint("Simple Person");

            var clone1 = ceras.Deserialize <Person>(data);

            Console.WriteLine($"Clone: Name={clone1.Name}, Health={clone1.Health}");



            // 2.) Types
            // You can also serialize as <object>.
            // In that case the type information will be included.
            // If a type is written it will only be written ONCE, so a List<Person> will not suddenly waste a
            // ton of space by continously writing the type-names
            var objectData = ceras.Serialize <object>(person);

            objectData.VisualizePrint("Person as <object>");
            var objectClone = ceras.Deserialize <object>(objectData);



            //
            // 3.) Improvement:
            // Recycle the serialization buffer by keeping the reference to it around.
            // Optionally we can even let Ceras create (or resize) the buffer for us.
            byte[] buffer       = null;
            int    writtenBytes = ceras.Serialize(person, ref buffer);

            // Now we could send this over the network, for example:
            //   socket.Send(buffer, writtenBytes, SocketFlags.None);
            var clone2 = ceras.Deserialize <Person>(buffer);



            //
            // 4.)
            // Deciding what gets serialized
            // There are multiple ways to configure what members to serialize
            // Ceras determines member inclusion in this order:
            //
            //  - a. Any custom configuration using ConfigType<T> or ConfigType(type)
            //
            //  - b. [Include] and [Exclude] attributes on individual members
            //
            //  - c. [MemberConfig] attribute
            //
            //  - d. "DefaultTargets" setting in the SerializerConfig
            //       which defaults to 'TargetMember.PublicFields'
            //

            SerializerConfig config = new SerializerConfig();

            config.DefaultTargets = TargetMember.PublicProperties | TargetMember.PrivateFields;

            config.ConfigType <Person>()
            .ConfigMember(p => p.Name).Include()
            .ConfigMember(p => p.BestFriend).Include();



            //
            // 5.) Circular references
            // Serializers commonly have trouble serializing circular references.
            // Ceras supports every possible object-graph, and there's literally
            // nothing to do or configure, it just works out of the box.
            // Lets make an example anyway...

            var personA = new Person {
                Name = "alice"
            };
            var personB = new Person {
                Name = "bob"
            };

            personA.BestFriend = personB;
            personB.BestFriend = personA;

            var dataWithCircularReferences = ceras.Serialize(personA);

            dataWithCircularReferences.VisualizePrint("Circular references data");

            var cloneA = ceras.Deserialize <Person>(dataWithCircularReferences);

            if (cloneA.BestFriend.BestFriend.BestFriend.BestFriend.BestFriend.BestFriend == cloneA)
            {
                Console.WriteLine("Circular reference serialization working as intended!");
            }
            else
            {
                throw new Exception("There was some problem!");
            }


            // Works with self-references!
            // Ceras maintains object references while deserializing, even if the object a field/prop points to doesn't exist yet
            var personC = new Person {
                Name = "abc"
            };

            personC.BestFriend = personC;
            var cloneC = ceras.Deserialize <Person>(ceras.Serialize(personC));

            Debug.Assert(cloneC.BestFriend.BestFriend.BestFriend.BestFriend == cloneC);


            // Fully maintains identity of objects!
            // There is only one actual object instance here (personC). The array refers to the same object two times.
            // While Ceras deserializes the array it only creates a single instance of 'Person', exactly as intended.
            Person[] personArray = new Person[2];
            personArray[0] = personC;
            personArray[1] = personC;
            var personArrayClone = ceras.Deserialize <Person[]>(ceras.Serialize(personArray));

            Debug.Assert(personArray[0] == personArray[1]);
            Debug.Assert(ReferenceEquals(personArray[0], personArray[1]));
            Debug.Assert(personArray[0].BestFriend == personArray[1].BestFriend);
            Debug.Assert(personArray[0].BestFriend.BestFriend == personArray[1]);
        }
示例#18
0
        static void ExpressionTreesTest()
        {
            // Primitive test (private readonly in a base type)
            {
                SerializerConfig config = new SerializerConfig();
                config.ConfigType <ReadonlyTestClass>()
                .ConstructByUninitialized()
                .SetReadonlyHandling(ReadonlyFieldHandling.ForcedOverwrite)
                .SetTargetMembers(TargetMember.PrivateFields);

                var ceras = new CerasSerializer(config);

                var obj  = new ReadonlyTestClass("a");
                var data = ceras.Serialize(obj);

                var clone = ceras.Deserialize <ReadonlyTestClass>(data);

                Debug.Assert(obj.GetName() == clone.GetName());
                Debug.Assert(obj.GetBaseName() == clone.GetBaseName());

                Console.WriteLine();
            }

            // Small test 1
            {
                Expression <Func <string, int, char> > getCharAtIndex = (text, index) => text.ElementAt(index);
                MethodCallExpression body = (MethodCallExpression)getCharAtIndex.Body;

                // Serialize and deserialize delegate
                SerializerConfig config = new SerializerConfig();
                var ceras = new CerasSerializer(config);

                var data      = ceras.Serialize <object>(body);
                var dataAsStr = Encoding.ASCII.GetString(data).Replace('\0', ' ');

                var clonedExp = (MethodCallExpression)ceras.Deserialize <object>(data);

                Debug.Assert(clonedExp.Method == body.Method);
                Debug.Assert(clonedExp.Arguments.Count == body.Arguments.Count);
            }

            // Small test 2
            {
                // Test data
                string inputString = "abcdefgh";


                Expression <Func <string, int, char> > getCharAtIndex = (text, index) => (text.ElementAt(index).ToString() + text[index])[0];
                var  del1 = getCharAtIndex.Compile();
                char c1   = del1(inputString, 2);


                // Serialize and deserialize expression
                SerializerConfig config = new SerializerConfig();
                var ceras = new CerasSerializer(config);

                var data      = ceras.Serialize(getCharAtIndex);
                var dataAsStr = Encoding.ASCII.GetString(data).Replace('\0', ' ');

                var clonedExp = ceras.Deserialize <Expression <Func <string, int, char> > >(data);


                // Compile the restored expression, check if it works and returns the same result
                var del2 = clonedExp.Compile();

                // Check single case
                var c2 = del2(inputString, 2);
                Debug.Assert(c1 == c2);

                // Check all cases
                for (int i = 0; i < inputString.Length; i++)
                {
                    Debug.Assert(del1(inputString, i) == del2(inputString, i));
                }
            }
        }