You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sb...@apache.org on 2017/05/15 10:14:16 UTC

[3/7] ignite git commit: IGNITE-5207 .NET: Support non-Int32 enums

IGNITE-5207 .NET: Support non-Int32 enums

This closes #1933


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/ed4a7a13
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/ed4a7a13
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/ed4a7a13

Branch: refs/heads/ignite-5075-cacheStart
Commit: ed4a7a131ee92143f7dec003c445142af207ee96
Parents: 4b2b684
Author: Pavel Tupitsyn <pt...@apache.org>
Authored: Fri May 12 13:56:25 2017 +0300
Committer: Pavel Tupitsyn <pt...@apache.org>
Committed: Fri May 12 13:56:25 2017 +0300

----------------------------------------------------------------------
 .../Apache.Ignite.Core.Tests.csproj             |   1 +
 .../Binary/BinarySelfTest.cs                    |   7 +-
 .../Binary/EnumsTest.cs                         | 274 +++++++++++++++++++
 .../Compute/ComputeApiTest.cs                   |   2 +-
 .../Impl/Binary/BinaryObject.cs                 |   2 +-
 .../Impl/Binary/BinaryReflectiveActions.cs      |   6 +-
 .../Impl/Binary/BinarySystemHandlers.cs         | 271 +++++++++---------
 .../Impl/Binary/BinaryUtils.cs                  |  30 --
 .../Impl/Binary/BinaryWriter.cs                 |  48 +++-
 9 files changed, 441 insertions(+), 200 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/ed4a7a13/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
index 7adbbbe..1c84a4d 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
@@ -80,6 +80,7 @@
     <Compile Include="Binary\Serializable\CallbacksTest.cs" />
     <Compile Include="Binary\Serializable\DelegatesTest.cs" />
     <Compile Include="Binary\Serializable\BasicSerializableObjectsTest.cs" />
+    <Compile Include="Binary\EnumsTest.cs" />
     <Compile Include="Binary\Serializable\ObjectReferenceTests.cs" />
     <Compile Include="Binary\Serializable\PrimitivesTest.cs" />
     <Compile Include="Binary\Serializable\SqlDmlTest.cs" />

http://git-wip-us.apache.org/repos/asf/ignite/blob/ed4a7a13/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTest.cs
index bdc0d65..01f108e 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTest.cs
@@ -2436,12 +2436,7 @@ namespace Apache.Ignite.Core.Tests.Binary
             }
         }
 
-        public enum TestEnum
-        {
-            Val1, Val2, Val3 = 10
-        }
-
-        public enum TestEnum2
+        public enum TestEnum : short
         {
             Val1, Val2, Val3 = 10
         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/ed4a7a13/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/EnumsTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/EnumsTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/EnumsTest.cs
new file mode 100644
index 0000000..f896ef4
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/EnumsTest.cs
@@ -0,0 +1,274 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Tests.Binary
+{
+    using System;
+    using System.Runtime.Serialization;
+    using Apache.Ignite.Core.Binary;
+    using Apache.Ignite.Core.Impl.Binary;
+    using Apache.Ignite.Core.Impl.Common;
+    using NUnit.Framework;
+
+    /// <summary>
+    /// Tests enums serialization.
+    /// </summary>
+    public class EnumsTest
+    {
+        /// <summary>
+        /// Tests direct enum value serialization.
+        /// </summary>
+        [Test]
+        public void TestDirectValue()
+        {
+            CheckValue(ByteEnum.Foo);
+            CheckValue(ByteEnum.Bar);
+
+            CheckValue(SByteEnum.Foo);
+            CheckValue(SByteEnum.Bar);
+
+            CheckValue(ShortEnum.Foo);
+            CheckValue(ShortEnum.Bar);
+            
+            CheckValue(UShortEnum.Foo);
+            CheckValue(UShortEnum.Bar);
+            
+            CheckValue(IntEnum.Foo);
+            CheckValue(IntEnum.Bar);
+            
+            CheckValue(UIntEnum.Foo);
+            CheckValue(UIntEnum.Bar);
+
+            CheckValue(LongEnum.Foo, false);
+            CheckValue(LongEnum.Bar, false);
+            
+            CheckValue(ULongEnum.Foo, false);
+            CheckValue(ULongEnum.Bar, false);
+        }
+
+        /// <summary>
+        /// Checks the enum value serialization.
+        /// </summary>
+        private static void CheckValue<T>(T val, bool isBinaryEnum = true)
+        {
+            var marsh = new Marshaller(null) {CompactFooter = false};
+            var bytes = marsh.Marshal(val);
+            var res = marsh.Unmarshal<T>(bytes);
+            var binRes = marsh.Unmarshal<IBinaryObject>(bytes, BinaryMode.ForceBinary);
+
+            Assert.AreEqual(val, res);
+            Assert.AreEqual(val, binRes.Deserialize<T>());
+
+            if (isBinaryEnum)
+            {
+                Assert.AreEqual(TypeCaster<int>.Cast(val), binRes.EnumValue);
+            }
+            else
+            {
+                Assert.AreEqual(val, binRes.GetField<T>("value__"));
+            }
+
+            // Check array.
+            var arr = new[] {val, val};
+            var arrRes = TestUtils.SerializeDeserialize(arr);
+
+            Assert.AreEqual(arr, arrRes);
+        }
+
+        /// <summary>
+        /// Tests enums as a field in binarizable object.
+        /// </summary>
+        [Test]
+        public void TestBinarizableField()
+        {
+            // Min values.
+            var val = new EnumsBinarizable();
+            
+            var res = TestUtils.SerializeDeserialize(val);
+            Assert.AreEqual(val, res);
+
+            // Max values.
+            val = new EnumsBinarizable
+            {
+                Byte = ByteEnum.Bar,
+                Int = IntEnum.Bar,
+                Long = LongEnum.Bar,
+                SByte = SByteEnum.Bar,
+                Short = ShortEnum.Bar,
+                UInt = UIntEnum.Bar,
+                ULong = ULongEnum.Bar,
+                UShort = UShortEnum.Bar
+            };
+
+            res = TestUtils.SerializeDeserialize(val);
+            Assert.AreEqual(val, res);
+        }
+
+        /// <summary>
+        /// Tests enums as a field in ISerializable object.
+        /// </summary>
+        [Test]
+        public void TestSerializableField()
+        {
+            // Min values.
+            var val = new EnumsSerializable();
+
+            var res = TestUtils.SerializeDeserialize(val);
+            Assert.AreEqual(val, res);
+
+            // Max values.
+            val = new EnumsSerializable
+            {
+                Byte = ByteEnum.Bar,
+                Int = IntEnum.Bar,
+                Long = LongEnum.Bar,
+                SByte = SByteEnum.Bar,
+                Short = ShortEnum.Bar,
+                UInt = UIntEnum.Bar,
+                ULong = ULongEnum.Bar,
+                UShort = UShortEnum.Bar
+            };
+
+            res = TestUtils.SerializeDeserialize(val);
+            Assert.AreEqual(val, res);
+        }
+
+        private enum ByteEnum : byte
+        {
+            Foo = byte.MinValue,
+            Bar = byte.MaxValue
+        }
+
+        private enum SByteEnum : sbyte
+        {
+            Foo = sbyte.MinValue,
+            Bar = sbyte.MaxValue
+        }
+
+        private enum ShortEnum : short
+        {
+            Foo = short.MinValue,
+            Bar = short.MaxValue
+        }
+
+        private enum UShortEnum : ushort
+        {
+            Foo = ushort.MinValue,
+            Bar = ushort.MaxValue
+        }
+
+        private enum IntEnum
+        {
+            Foo = int.MinValue,
+            Bar = int.MaxValue
+        }
+
+        private enum UIntEnum : uint
+        {
+            Foo = uint.MinValue,
+            Bar = uint.MaxValue
+        }
+
+        private enum LongEnum : long
+        {
+            Foo = long.MinValue,
+            Bar = long.MaxValue
+        }
+
+        private enum ULongEnum : ulong
+        {
+            Foo = ulong.MinValue,
+            Bar = ulong.MaxValue
+        }
+
+        private class EnumsBinarizable
+        {
+            public ByteEnum Byte { get; set; }
+            public SByteEnum SByte { get; set; }
+            public ShortEnum Short { get; set; }
+            public UShortEnum UShort { get; set; }
+            public IntEnum Int { get; set; }
+            public UIntEnum UInt { get; set; }
+            public LongEnum Long { get; set; }
+            public ULongEnum ULong { get; set; }
+
+            private bool Equals(EnumsBinarizable other)
+            {
+                return Byte == other.Byte && SByte == other.SByte && Short == other.Short 
+                    && UShort == other.UShort && Int == other.Int && UInt == other.UInt 
+                    && Long == other.Long && ULong == other.ULong;
+            }
+
+            public override bool Equals(object obj)
+            {
+                if (ReferenceEquals(null, obj)) return false;
+                if (ReferenceEquals(this, obj)) return true;
+                if (obj.GetType() != GetType()) return false;
+                return Equals((EnumsBinarizable) obj);
+            }
+
+            public override int GetHashCode()
+            {
+                unchecked
+                {
+                    var hashCode = (int) Byte;
+                    hashCode = (hashCode * 397) ^ (int) SByte;
+                    hashCode = (hashCode * 397) ^ (int) Short;
+                    hashCode = (hashCode * 397) ^ (int) UShort;
+                    hashCode = (hashCode * 397) ^ (int) Int;
+                    hashCode = (hashCode * 397) ^ (int) UInt;
+                    hashCode = (hashCode * 397) ^ Long.GetHashCode();
+                    hashCode = (hashCode * 397) ^ ULong.GetHashCode();
+                    return hashCode;
+                }
+            }
+        }
+
+        [Serializable]
+        private class EnumsSerializable : EnumsBinarizable, ISerializable
+        {
+            public EnumsSerializable()
+            {
+                // No-op.
+            }
+
+            protected EnumsSerializable(SerializationInfo info, StreamingContext context)
+            {
+                Byte = (ByteEnum) info.GetValue("byte", typeof(ByteEnum));
+                SByte = (SByteEnum) info.GetValue("sbyte", typeof(SByteEnum));
+                Short = (ShortEnum) info.GetValue("short", typeof(ShortEnum));
+                UShort = (UShortEnum) info.GetValue("ushort", typeof(UShortEnum));
+                Int = (IntEnum) info.GetValue("int", typeof(IntEnum));
+                UInt = (UIntEnum) info.GetValue("uint", typeof(UIntEnum));
+                Long = (LongEnum) info.GetValue("long", typeof(LongEnum));
+                ULong = (ULongEnum) info.GetValue("ulong", typeof(ULongEnum));
+            }
+
+            public void GetObjectData(SerializationInfo info, StreamingContext context)
+            {
+                info.AddValue("byte", Byte);
+                info.AddValue("sbyte", SByte);
+                info.AddValue("short", Short);
+                info.AddValue("ushort", UShort);
+                info.AddValue("int", Int);
+                info.AddValue("uint", UInt);
+                info.AddValue("long", Long);
+                info.AddValue("ulong", ULong);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/ed4a7a13/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeApiTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeApiTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeApiTest.cs
index e403d93..b9b7a04 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeApiTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeApiTest.cs
@@ -1532,7 +1532,7 @@ namespace Apache.Ignite.Core.Tests.Compute
         }
     }
 
-    public enum PlatformComputeEnum
+    public enum PlatformComputeEnum : ushort
     {
         Foo,
         Bar,

http://git-wip-us.apache.org/repos/asf/ignite/blob/ed4a7a13/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObject.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObject.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObject.cs
index 690a0a4..480e0e6 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObject.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObject.cs
@@ -132,7 +132,7 @@ namespace Apache.Ignite.Core.Impl.Binary
             get
             {
                 throw new NotSupportedException("IBinaryObject.Value is only supported for enums. " +
-                    "Check IBinaryObject.IsEnum property before accessing Value.");
+                    "Check IBinaryObject.GetBinaryType().IsEnum property before accessing Value.");
             }
         }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/ed4a7a13/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReflectiveActions.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReflectiveActions.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReflectiveActions.cs
index 907b465..6aaf5f9 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReflectiveActions.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReflectiveActions.cs
@@ -476,7 +476,7 @@ namespace Apache.Ignite.Core.Impl.Binary
                     : GetWriter<Guid?>(field, (f, w, o) => w.WriteGuid(f, o));
                 readAction = raw ? GetRawReader(field, r => r.ReadGuid()) : GetReader(field, (f, r) => r.ReadGuid(f));
             }
-            else if (type.IsEnum)
+            else if (type.IsEnum && !new[] {typeof(long), typeof(ulong)}.Contains(Enum.GetUnderlyingType(type)))
             {
                 writeAction = raw
                     ? GetRawWriter<object>(field, (w, o) => w.WriteEnum(o), true)
@@ -503,7 +503,7 @@ namespace Apache.Ignite.Core.Impl.Binary
                     ? GetRawReader(field, r => r.ReadCollection())
                     : GetReader(field, (f, r) => r.ReadCollection(f));
             }
-            else if (type == typeof (DateTime) && IsQueryField(field) && !raw)
+            else if (type == typeof(DateTime) && IsQueryField(field) && !raw)
             {
                 // Special case for DateTime and query fields.
                 // If a field is marked with [QuerySqlField], write it as TimeStamp so that queries work.
@@ -514,7 +514,7 @@ namespace Apache.Ignite.Core.Impl.Binary
                 writeAction = GetWriter<DateTime>(field, (f, w, o) => w.WriteTimestamp(f, o));
                 readAction = GetReader(field, (f, r) => r.ReadObject<DateTime>(f));
             }
-            else if (nullableType == typeof (DateTime) && IsQueryField(field) && !raw)
+            else if (nullableType == typeof(DateTime) && IsQueryField(field) && !raw)
             {
                 writeAction = GetWriter<DateTime?>(field, (f, w, o) => w.WriteTimestamp(f, o));
                 readAction = GetReader(field, (f, r) => r.ReadTimestamp(f));

http://git-wip-us.apache.org/repos/asf/ignite/blob/ed4a7a13/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs
index a30b981..1dfc3b6 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs
@@ -31,8 +31,8 @@ namespace Apache.Ignite.Core.Impl.Binary
     internal static class BinarySystemHandlers
     {
         /** Write handlers. */
-        private static readonly CopyOnWriteConcurrentDictionary<Type, BinarySystemWriteHandler> WriteHandlers =
-            new CopyOnWriteConcurrentDictionary<Type, BinarySystemWriteHandler>();
+        private static readonly CopyOnWriteConcurrentDictionary<Type, IBinarySystemWriteHandler> WriteHandlers =
+            new CopyOnWriteConcurrentDictionary<Type, IBinarySystemWriteHandler>();
 
         /** Read handlers. */
         private static readonly IBinarySystemReader[] ReadHandlers = new IBinarySystemReader[255];
@@ -160,15 +160,11 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// </summary>
         /// <param name="type"></param>
         /// <returns></returns>
-        public static BinarySystemWriteHandler GetWriteHandler(Type type)
+        public static IBinarySystemWriteHandler GetWriteHandler(Type type)
         {
             return WriteHandlers.GetOrAdd(type, t =>
             {
-                bool supportsHandles;
-
-                var handler = FindWriteHandler(t, out supportsHandles);
-
-                return handler == null ? null : new BinarySystemWriteHandler(handler, supportsHandles);
+                return FindWriteHandler(t);
             });
         }
 
@@ -176,37 +172,49 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// Find write handler for type.
         /// </summary>
         /// <param name="type">Type.</param>
-        /// <param name="supportsHandles">Flag indicating whether returned delegate supports handles.</param>
         /// <returns>
         /// Write handler or NULL.
         /// </returns>
-        private static Action<BinaryWriter, object> FindWriteHandler(Type type, out bool supportsHandles)
+        private static IBinarySystemWriteHandler FindWriteHandler(Type type)
         {
-            supportsHandles = false;
-
             // 1. Well-known types.
             if (type == typeof(string))
-                return WriteString;
+                return new BinarySystemWriteHandler<string>(WriteString, false);
             if (type == typeof(decimal))
-                return WriteDecimal;
+                return new BinarySystemWriteHandler<decimal>(WriteDecimal, false);
             if (type == typeof(Guid))
-                return WriteGuid;
+                return new BinarySystemWriteHandler<Guid>(WriteGuid, false);
             if (type == typeof (BinaryObject))
-                return WriteBinary;
+                return new BinarySystemWriteHandler<BinaryObject>(WriteBinary, false);
             if (type == typeof (BinaryEnum))
-                return WriteBinaryEnum;
+                return new BinarySystemWriteHandler<BinaryEnum>(WriteBinaryEnum, false);
             if (type.IsEnum)
-                return WriteEnum;
+            {
+                var underlyingType = Enum.GetUnderlyingType(type);
+
+                if (underlyingType == typeof(int))
+                    return new BinarySystemWriteHandler<int>((w, i) => w.WriteEnum(i, type), false);
+                if (underlyingType == typeof(uint))
+                    return new BinarySystemWriteHandler<uint>((w, i) => w.WriteEnum(unchecked((int) i), type), false);
+                if (underlyingType == typeof(byte))
+                    return new BinarySystemWriteHandler<byte>((w, i) => w.WriteEnum(i, type), false);
+                if (underlyingType == typeof(sbyte))
+                    return new BinarySystemWriteHandler<sbyte>((w, i) => w.WriteEnum(i, type), false);
+                if (underlyingType == typeof(short))
+                    return new BinarySystemWriteHandler<short>((w, i) => w.WriteEnum(i, type), false);
+                if (underlyingType == typeof(ushort))
+                    return new BinarySystemWriteHandler<ushort>((w, i) => w.WriteEnum(i, type), false);
+
+                return null; // Other enums, such as long and ulong, can't be expressed as int.
+            }
             if (type == typeof(Ignite))
-                return WriteIgnite;
+                return new BinarySystemWriteHandler<object>(WriteIgnite, false);
 
             // All types below can be written as handles.
-            supportsHandles = true;
-
             if (type == typeof (ArrayList))
-                return WriteArrayList;
+                return new BinarySystemWriteHandler<ICollection>(WriteArrayList, true);
             if (type == typeof (Hashtable))
-                return WriteHashtable;
+                return new BinarySystemWriteHandler<IDictionary>(WriteHashtable, true);
 
             if (type.IsArray)
             {
@@ -215,49 +223,66 @@ namespace Apache.Ignite.Core.Impl.Binary
                 
                 // Primitives.
                 if (elemType == typeof (bool))
-                    return WriteBoolArray;
+                    return new BinarySystemWriteHandler<bool[]>(WriteBoolArray, true);
                 if (elemType == typeof(byte))
-                    return WriteByteArray;
+                    return new BinarySystemWriteHandler<byte[]>(WriteByteArray, true);
                 if (elemType == typeof(short))
-                    return WriteShortArray;
+                    return new BinarySystemWriteHandler<short[]>(WriteShortArray, true);
                 if (elemType == typeof(char))
-                    return WriteCharArray;
+                    return new BinarySystemWriteHandler<char[]>(WriteCharArray, true);
                 if (elemType == typeof(int))
-                    return WriteIntArray;
+                    return new BinarySystemWriteHandler<int[]>(WriteIntArray, true);
                 if (elemType == typeof(long))
-                    return WriteLongArray;
+                    return new BinarySystemWriteHandler<long[]>(WriteLongArray, true);
                 if (elemType == typeof(float))
-                    return WriteFloatArray;
+                    return new BinarySystemWriteHandler<float[]>(WriteFloatArray, true);
                 if (elemType == typeof(double))
-                    return WriteDoubleArray;
+                    return new BinarySystemWriteHandler<double[]>(WriteDoubleArray, true);
                 // Non-CLS primitives.
                 if (elemType == typeof(sbyte))
-                    return WriteSbyteArray;
+                    return new BinarySystemWriteHandler<byte[]>(WriteByteArray, true);
                 if (elemType == typeof(ushort))
-                    return WriteUshortArray;
+                    return new BinarySystemWriteHandler<short[]>(WriteShortArray, true);
                 if (elemType == typeof(uint))
-                    return WriteUintArray;
+                    return new BinarySystemWriteHandler<int[]>(WriteIntArray, true);
                 if (elemType == typeof(ulong))
-                    return WriteUlongArray;
+                    return new BinarySystemWriteHandler<long[]>(WriteLongArray, true);
                 // Special types.
                 if (elemType == typeof (decimal?))
-                    return WriteDecimalArray;
+                    return new BinarySystemWriteHandler<decimal?[]>(WriteDecimalArray, true);
                 if (elemType == typeof(string))
-                    return WriteStringArray;
+                    return new BinarySystemWriteHandler<string[]>(WriteStringArray, true);
                 if (elemType == typeof(Guid?))
-                    return WriteGuidArray;
+                    return new BinarySystemWriteHandler<Guid?[]>(WriteGuidArray, true);
                 // Enums.
-                if (elemType.IsEnum || elemType == typeof(BinaryEnum))
-                    return WriteEnumArray;
+                if (IsIntEnum(elemType) || elemType == typeof(BinaryEnum))
+                    return new BinarySystemWriteHandler<object>(WriteEnumArray, true);
 
                 // Object array.
-                return WriteArray;
+                return new BinarySystemWriteHandler<object>(WriteArray, true);
             }
 
             return null;
         }
 
         /// <summary>
+        /// Determines whether specified type is an enum which fits into Int32.
+        /// </summary>
+        private static bool IsIntEnum(Type type)
+        {
+            if (!type.IsEnum)
+                return false;
+
+            var underlyingType = Enum.GetUnderlyingType(type);
+
+            return underlyingType == typeof(int) 
+                || underlyingType == typeof(short)
+                || underlyingType == typeof(ushort)
+                || underlyingType == typeof(byte)
+                || underlyingType == typeof(sbyte);
+        }
+
+        /// <summary>
         /// Find write handler for type.
         /// </summary>
         /// <param name="type">Type.</param>
@@ -300,11 +325,11 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// </summary>
         /// <param name="ctx">Context.</param>
         /// <param name="obj">Value.</param>
-        private static void WriteDecimal(BinaryWriter ctx, object obj)
+        private static void WriteDecimal(BinaryWriter ctx, decimal obj)
         {
             ctx.Stream.WriteByte(BinaryUtils.TypeDecimal);
 
-            BinaryUtils.WriteDecimal((decimal)obj, ctx.Stream);
+            BinaryUtils.WriteDecimal(obj, ctx.Stream);
         }
         
         /// <summary>
@@ -312,11 +337,11 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// </summary>
         /// <param name="ctx">Context.</param>
         /// <param name="obj">Object.</param>
-        private static void WriteString(BinaryWriter ctx, object obj)
+        private static void WriteString(BinaryWriter ctx, string obj)
         {
             ctx.Stream.WriteByte(BinaryUtils.TypeString);
 
-            BinaryUtils.WriteString((string)obj, ctx.Stream);
+            BinaryUtils.WriteString(obj, ctx.Stream);
         }
 
         /// <summary>
@@ -324,11 +349,11 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// </summary>
         /// <param name="ctx">Context.</param>
         /// <param name="obj">Value.</param>
-        private static void WriteGuid(BinaryWriter ctx, object obj)
+        private static void WriteGuid(BinaryWriter ctx, Guid obj)
         {
             ctx.Stream.WriteByte(BinaryUtils.TypeGuid);
 
-            BinaryUtils.WriteGuid((Guid)obj, ctx.Stream);
+            BinaryUtils.WriteGuid(obj, ctx.Stream);
         }
 
         /// <summary>
@@ -336,11 +361,11 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// </summary>
         /// <param name="ctx">Context.</param>
         /// <param name="obj">Value.</param>
-        private static void WriteBoolArray(BinaryWriter ctx, object obj)
+        private static void WriteBoolArray(BinaryWriter ctx, bool[] obj)
         {
             ctx.Stream.WriteByte(BinaryUtils.TypeArrayBool);
 
-            BinaryUtils.WriteBooleanArray((bool[])obj, ctx.Stream);
+            BinaryUtils.WriteBooleanArray(obj, ctx.Stream);
         }
         
         /// <summary>
@@ -348,23 +373,11 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// </summary>
         /// <param name="ctx">Context.</param>
         /// <param name="obj">Value.</param>
-        private static void WriteByteArray(BinaryWriter ctx, object obj)
-        {
-            ctx.Stream.WriteByte(BinaryUtils.TypeArrayByte);
-
-            BinaryUtils.WriteByteArray((byte[])obj, ctx.Stream);
-        }
-
-        /// <summary>
-        /// Write sbyte array.
-        /// </summary>
-        /// <param name="ctx">Context.</param>
-        /// <param name="obj">Value.</param>
-        private static void WriteSbyteArray(BinaryWriter ctx, object obj)
+        private static void WriteByteArray(BinaryWriter ctx, byte[] obj)
         {
             ctx.Stream.WriteByte(BinaryUtils.TypeArrayByte);
 
-            BinaryUtils.WriteByteArray((byte[]) obj, ctx.Stream);
+            BinaryUtils.WriteByteArray(obj, ctx.Stream);
         }
 
         /// <summary>
@@ -372,26 +385,14 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// </summary>
         /// <param name="ctx">Context.</param>
         /// <param name="obj">Value.</param>
-        private static void WriteShortArray(BinaryWriter ctx, object obj)
+        private static void WriteShortArray(BinaryWriter ctx, short[] obj)
         {
             ctx.Stream.WriteByte(BinaryUtils.TypeArrayShort);
 
-            BinaryUtils.WriteShortArray((short[])obj, ctx.Stream);
+            BinaryUtils.WriteShortArray(obj, ctx.Stream);
         }
         
         /// <summary>
-        /// Write ushort array.
-        /// </summary>
-        /// <param name="ctx">Context.</param>
-        /// <param name="obj">Value.</param>
-        private static void WriteUshortArray(BinaryWriter ctx, object obj)
-        {
-            ctx.Stream.WriteByte(BinaryUtils.TypeArrayShort);
-
-            BinaryUtils.WriteShortArray((short[]) obj, ctx.Stream);
-        }
-
-        /// <summary>
         /// Write char array.
         /// </summary>
         /// <param name="ctx">Context.</param>
@@ -408,23 +409,11 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// </summary>
         /// <param name="ctx">Context.</param>
         /// <param name="obj">Value.</param>
-        private static void WriteIntArray(BinaryWriter ctx, object obj)
+        private static void WriteIntArray(BinaryWriter ctx, int[] obj)
         {
             ctx.Stream.WriteByte(BinaryUtils.TypeArrayInt);
 
-            BinaryUtils.WriteIntArray((int[])obj, ctx.Stream);
-        }
-
-        /// <summary>
-        /// Write uint array.
-        /// </summary>
-        /// <param name="ctx">Context.</param>
-        /// <param name="obj">Value.</param>
-        private static void WriteUintArray(BinaryWriter ctx, object obj)
-        {
-            ctx.Stream.WriteByte(BinaryUtils.TypeArrayInt);
-
-            BinaryUtils.WriteIntArray((int[]) obj, ctx.Stream);
+            BinaryUtils.WriteIntArray(obj, ctx.Stream);
         }
 
         /// <summary>
@@ -432,23 +421,11 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// </summary>
         /// <param name="ctx">Context.</param>
         /// <param name="obj">Value.</param>
-        private static void WriteLongArray(BinaryWriter ctx, object obj)
-        {
-            ctx.Stream.WriteByte(BinaryUtils.TypeArrayLong);
-
-            BinaryUtils.WriteLongArray((long[])obj, ctx.Stream);
-        }
-
-        /// <summary>
-        /// Write ulong array.
-        /// </summary>
-        /// <param name="ctx">Context.</param>
-        /// <param name="obj">Value.</param>
-        private static void WriteUlongArray(BinaryWriter ctx, object obj)
+        private static void WriteLongArray(BinaryWriter ctx, long[] obj)
         {
             ctx.Stream.WriteByte(BinaryUtils.TypeArrayLong);
 
-            BinaryUtils.WriteLongArray((long[]) obj, ctx.Stream);
+            BinaryUtils.WriteLongArray(obj, ctx.Stream);
         }
 
         /// <summary>
@@ -456,11 +433,11 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// </summary>
         /// <param name="ctx">Context.</param>
         /// <param name="obj">Value.</param>
-        private static void WriteFloatArray(BinaryWriter ctx, object obj)
+        private static void WriteFloatArray(BinaryWriter ctx, float[] obj)
         {
             ctx.Stream.WriteByte(BinaryUtils.TypeArrayFloat);
 
-            BinaryUtils.WriteFloatArray((float[])obj, ctx.Stream);
+            BinaryUtils.WriteFloatArray(obj, ctx.Stream);
         }
 
         /// <summary>
@@ -468,11 +445,11 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// </summary>
         /// <param name="ctx">Context.</param>
         /// <param name="obj">Value.</param>
-        private static void WriteDoubleArray(BinaryWriter ctx, object obj)
+        private static void WriteDoubleArray(BinaryWriter ctx, double[] obj)
         {
             ctx.Stream.WriteByte(BinaryUtils.TypeArrayDouble);
 
-            BinaryUtils.WriteDoubleArray((double[])obj, ctx.Stream);
+            BinaryUtils.WriteDoubleArray(obj, ctx.Stream);
         }
 
         /// <summary>
@@ -480,11 +457,11 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// </summary>
         /// <param name="ctx">Context.</param>
         /// <param name="obj">Value.</param>
-        private static void WriteDecimalArray(BinaryWriter ctx, object obj)
+        private static void WriteDecimalArray(BinaryWriter ctx, decimal?[] obj)
         {
             ctx.Stream.WriteByte(BinaryUtils.TypeArrayDecimal);
 
-            BinaryUtils.WriteDecimalArray((decimal?[])obj, ctx.Stream);
+            BinaryUtils.WriteDecimalArray(obj, ctx.Stream);
         }
         
         /// <summary>
@@ -492,11 +469,11 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// </summary>
         /// <param name="ctx">Context.</param>
         /// <param name="obj">Value.</param>
-        private static void WriteStringArray(BinaryWriter ctx, object obj)
+        private static void WriteStringArray(BinaryWriter ctx, string[] obj)
         {
             ctx.Stream.WriteByte(BinaryUtils.TypeArrayString);
 
-            BinaryUtils.WriteStringArray((string[])obj, ctx.Stream);
+            BinaryUtils.WriteStringArray(obj, ctx.Stream);
         }
         
         /// <summary>
@@ -504,11 +481,11 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// </summary>
         /// <param name="ctx">Context.</param>
         /// <param name="obj">Value.</param>
-        private static void WriteGuidArray(BinaryWriter ctx, object obj)
+        private static void WriteGuidArray(BinaryWriter ctx, Guid?[] obj)
         {
             ctx.Stream.WriteByte(BinaryUtils.TypeArrayGuid);
 
-            BinaryUtils.WriteGuidArray((Guid?[])obj, ctx.Stream);
+            BinaryUtils.WriteGuidArray(obj, ctx.Stream);
         }
 
         /// <summary>
@@ -534,47 +511,39 @@ namespace Apache.Ignite.Core.Impl.Binary
         /**
          * <summary>Write ArrayList.</summary>
          */
-        private static void WriteArrayList(BinaryWriter ctx, object obj)
+        private static void WriteArrayList(BinaryWriter ctx, ICollection obj)
         {
             ctx.Stream.WriteByte(BinaryUtils.TypeCollection);
 
-            BinaryUtils.WriteCollection((ICollection)obj, ctx, BinaryUtils.CollectionArrayList);
+            BinaryUtils.WriteCollection(obj, ctx, BinaryUtils.CollectionArrayList);
         }
 
         /**
          * <summary>Write Hashtable.</summary>
          */
-        private static void WriteHashtable(BinaryWriter ctx, object obj)
+        private static void WriteHashtable(BinaryWriter ctx, IDictionary obj)
         {
             ctx.Stream.WriteByte(BinaryUtils.TypeDictionary);
 
-            BinaryUtils.WriteDictionary((IDictionary)obj, ctx, BinaryUtils.MapHashMap);
+            BinaryUtils.WriteDictionary(obj, ctx, BinaryUtils.MapHashMap);
         }
 
         /**
          * <summary>Write binary object.</summary>
          */
-        private static void WriteBinary(BinaryWriter ctx, object obj)
+        private static void WriteBinary(BinaryWriter ctx, BinaryObject obj)
         {
             ctx.Stream.WriteByte(BinaryUtils.TypeBinary);
 
-            BinaryUtils.WriteBinary(ctx.Stream, (BinaryObject)obj);
+            BinaryUtils.WriteBinary(ctx.Stream, obj);
         }
         
         /// <summary>
         /// Write enum.
         /// </summary>
-        private static void WriteEnum(BinaryWriter ctx, object obj)
+        private static void WriteBinaryEnum(BinaryWriter ctx, BinaryEnum obj)
         {
-            ctx.WriteEnum(obj);
-        }
-
-        /// <summary>
-        /// Write enum.
-        /// </summary>
-        private static void WriteBinaryEnum(BinaryWriter ctx, object obj)
-        {
-            var binEnum = (BinaryEnum) obj;
+            var binEnum = obj;
 
             ctx.Stream.WriteByte(BinaryUtils.TypeEnum);
 
@@ -790,20 +759,38 @@ namespace Apache.Ignite.Core.Impl.Binary
     /// <summary>
     /// Write delegate + handles flag.
     /// </summary>
-    internal class BinarySystemWriteHandler
+    internal interface IBinarySystemWriteHandler
+    {
+        /// <summary>
+        /// Gets a value indicating whether this handler supports handles.
+        /// </summary>
+        bool SupportsHandles { get; }
+
+        /// <summary>
+        /// Writes object to a specified writer.
+        /// </summary>
+        /// <param name="writer">The writer.</param>
+        /// <param name="obj">The object.</param>
+        void Write<T>(BinaryWriter writer, T obj);
+    }
+
+    /// <summary>
+    /// Write delegate + handles flag.
+    /// </summary>
+    internal class BinarySystemWriteHandler<T1> : IBinarySystemWriteHandler
     {
         /** */
-        private readonly Action<BinaryWriter, object> _writeAction;
+        private readonly Action<BinaryWriter, T1> _writeAction;
 
         /** */
         private readonly bool _supportsHandles;
 
         /// <summary>
-        /// Initializes a new instance of the <see cref="BinarySystemWriteHandler" /> class.
+        /// Initializes a new instance of the <see cref="BinarySystemWriteHandler{T1}" /> class.
         /// </summary>
         /// <param name="writeAction">The write action.</param>
         /// <param name="supportsHandles">Handles flag.</param>
-        public BinarySystemWriteHandler(Action<BinaryWriter, object> writeAction, bool supportsHandles)
+        public BinarySystemWriteHandler(Action<BinaryWriter, T1> writeAction, bool supportsHandles)
         {
             Debug.Assert(writeAction != null);
 
@@ -811,19 +798,13 @@ namespace Apache.Ignite.Core.Impl.Binary
             _supportsHandles = supportsHandles;
         }
 
-        /// <summary>
-        /// Writes object to a specified writer.
-        /// </summary>
-        /// <param name="writer">The writer.</param>
-        /// <param name="obj">The object.</param>
-        public void Write(BinaryWriter writer, object obj)
+        /** <inheritdoc /> */
+        public void Write<T>(BinaryWriter writer, T obj)
         {
-            _writeAction(writer, obj);
+            _writeAction(writer, TypeCaster<T1>.Cast(obj));
         }
 
-        /// <summary>
-        /// Gets a value indicating whether this handler supports handles.
-        /// </summary>
+        /** <inheritdoc /> */
         public bool SupportsHandles
         {
             get { return _supportsHandles; }

http://git-wip-us.apache.org/repos/asf/ignite/blob/ed4a7a13/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs
index dee0a80..5bc68fe 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs
@@ -1440,36 +1440,6 @@ namespace Apache.Ignite.Core.Impl.Binary
         }
 
         /// <summary>
-        /// Write enum.
-        /// </summary>
-        /// <param name="writer">Writer.</param>
-        /// <param name="val">Value.</param>
-        public static void WriteEnum<T>(BinaryWriter writer, T val)
-        {
-            writer.WriteInt(GetEnumTypeId(val.GetType(), writer.Marshaller));
-            writer.WriteInt(TypeCaster<int>.Cast(val));
-        }
-
-        /// <summary>
-        /// Gets the enum type identifier.
-        /// </summary>
-        /// <param name="enumType">The enum type.</param>
-        /// <param name="marshaller">The marshaller.</param>
-        /// <returns>Enum type id.</returns>
-        private static int GetEnumTypeId(Type enumType, Marshaller marshaller)
-        {
-            if (Enum.GetUnderlyingType(enumType) == TypInt)
-            {
-                var desc = marshaller.GetDescriptor(enumType);
-
-                return desc.TypeId;
-            }
-
-            throw new BinaryObjectException("Only Int32 underlying type is supported for enums: " +
-                                            enumType.Name);
-        }
-
-        /// <summary>
         /// Gets the enum value by type id and int representation.
         /// </summary>
         /// <typeparam name="T">Result type.</typeparam>

http://git-wip-us.apache.org/repos/asf/ignite/blob/ed4a7a13/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs
index 12cc026..56774d4 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs
@@ -858,19 +858,47 @@ namespace Apache.Ignite.Core.Impl.Binary
                 WriteNullField();
             else
             {
-                var desc = _marsh.GetDescriptor(val.GetType());
+                var type = val.GetType();
 
-                var metaHnd = _marsh.GetBinaryTypeHandler(desc);
-
-                _stream.WriteByte(BinaryUtils.TypeEnum);
+                if (!type.IsEnum)
+                {
+                    throw new BinaryObjectException("Type is not an enum: " + type);
+                }
 
-                BinaryUtils.WriteEnum(this, val);
+                var handler = BinarySystemHandlers.GetWriteHandler(type);
 
-                SaveMetadata(desc, metaHnd.OnObjectWriteFinished());
+                if (handler != null)
+                {
+                    // All enums except long/ulong.
+                    handler.Write(this, val);
+                }
+                else
+                {
+                    throw new BinaryObjectException(string.Format("Enum '{0}' has unsupported underlying type '{1}'. " +
+                                                                  "Use WriteObject instead of WriteEnum.",
+                        type, Enum.GetUnderlyingType(type)));
+                }
             }
         }
 
         /// <summary>
+        /// Write enum value.
+        /// </summary>
+        /// <param name="val">Enum value.</param>
+        /// <param name="type">Enum type.</param>
+        internal void WriteEnum(int val, Type type)
+        {
+            var desc = _marsh.GetDescriptor(type);
+
+            _stream.WriteByte(BinaryUtils.TypeEnum);
+            _stream.WriteInt(desc.TypeId);
+            _stream.WriteInt(val);
+
+            var metaHnd = _marsh.GetBinaryTypeHandler(desc);
+            SaveMetadata(desc, metaHnd.OnObjectWriteFinished());
+        }
+
+        /// <summary>
         /// Write named enum array.
         /// </summary>
         /// <typeparam name="T"></typeparam>
@@ -1120,14 +1148,6 @@ namespace Apache.Ignite.Core.Impl.Binary
                 return;
             }
 
-            // Handle enums.
-            if (type.IsEnum)
-            {
-                WriteEnum(obj);
-
-                return;
-            }
-
             // Handle special case for builder.
             if (WriteBuilderSpecials(obj))
                 return;