You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by vo...@apache.org on 2015/09/21 16:27:32 UTC

[36/52] [partial] ignite git commit: IGNITE-1513: Moved .Net.

http://git-wip-us.apache.org/repos/asf/ignite/blob/f2eb16cd/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Io/PortableHeapStream.cs
----------------------------------------------------------------------
diff --git a/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Io/PortableHeapStream.cs b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Io/PortableHeapStream.cs
new file mode 100644
index 0000000..690f92c
--- /dev/null
+++ b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Io/PortableHeapStream.cs
@@ -0,0 +1,447 @@
+/*
+ * 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.Impl.Portable.IO
+{
+    using System;
+    using System.IO;
+    using System.Text;
+
+    /// <summary>
+    /// Portable onheap stream.
+    /// </summary>
+    internal unsafe class PortableHeapStream : PortableAbstractStream
+    {
+        /** Data array. */
+        protected byte[] Data;
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        /// <param name="cap">Initial capacity.</param>
+        public PortableHeapStream(int cap)
+        {
+            Data = new byte[cap];
+        }
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        /// <param name="data">Data array.</param>
+        public PortableHeapStream(byte[] data)
+        {
+            Data = data;
+        }
+
+        /** <inheritdoc /> */
+        public override void WriteByte(byte val)
+        {
+            int pos0 = EnsureWriteCapacityAndShift(1);
+
+            Data[pos0] = val;
+        }
+
+        /** <inheritdoc /> */
+        public override byte ReadByte()
+        {
+            int pos0 = EnsureReadCapacityAndShift(1);
+
+            return Data[pos0];
+        }
+
+        /** <inheritdoc /> */
+        public override void WriteByteArray(byte[] val)
+        {
+            int pos0 = EnsureWriteCapacityAndShift(val.Length);
+
+            fixed (byte* data0 = Data)
+            {
+                WriteByteArray0(val, data0 + pos0);
+            }
+        }
+
+        /** <inheritdoc /> */
+        public override byte[] ReadByteArray(int cnt)
+        {
+            int pos0 = EnsureReadCapacityAndShift(cnt);
+
+            fixed (byte* data0 = Data)
+            {
+                return ReadByteArray0(cnt, data0 + pos0);
+            }
+        }
+
+        /** <inheritdoc /> */
+        public override void WriteBoolArray(bool[] val)
+        {
+            int pos0 = EnsureWriteCapacityAndShift(val.Length);
+
+            fixed (byte* data0 = Data)
+            {
+                WriteBoolArray0(val, data0 + pos0);
+            }
+        }
+
+        /** <inheritdoc /> */
+        public override bool[] ReadBoolArray(int cnt)
+        {
+            int pos0 = EnsureReadCapacityAndShift(cnt);
+
+            fixed (byte* data0 = Data)
+            {
+                return ReadBoolArray0(cnt, data0 + pos0);
+            }
+        }
+
+        /** <inheritdoc /> */
+        public override void WriteShort(short val)
+        {
+            int pos0 = EnsureWriteCapacityAndShift(2);
+
+            fixed (byte* data0 = Data)
+            {
+                WriteShort0(val, data0 + pos0);
+            }
+        }
+
+        /** <inheritdoc /> */
+        public override short ReadShort()
+        {
+            int pos0 = EnsureReadCapacityAndShift(2);
+
+            fixed (byte* data0 = Data)
+            {
+                return ReadShort0(data0 + pos0);
+            }
+        }
+
+        /** <inheritdoc /> */
+        public override void WriteShortArray(short[] val)
+        {
+            int cnt = val.Length << 1;
+
+            int pos0 = EnsureWriteCapacityAndShift(cnt);
+
+            fixed (byte* data0 = Data)
+            {
+                WriteShortArray0(val, data0 + pos0, cnt);
+            }
+        }
+
+        /** <inheritdoc /> */
+        public override short[] ReadShortArray(int cnt)
+        {
+            int cnt0 = cnt << 1;
+
+            int pos0 = EnsureReadCapacityAndShift(cnt0);
+
+            fixed (byte* data0 = Data)
+            {
+                return ReadShortArray0(cnt, data0 + pos0, cnt0);
+            }
+        }
+
+        /** <inheritdoc /> */
+        public override void WriteCharArray(char[] val)
+        {
+            int cnt = val.Length << 1;
+
+            int pos0 = EnsureWriteCapacityAndShift(cnt);
+
+            fixed (byte* data0 = Data)
+            {
+                WriteCharArray0(val, data0 + pos0, cnt);
+            }
+        }
+
+        /** <inheritdoc /> */
+        public override char[] ReadCharArray(int cnt)
+        {
+            int cnt0 = cnt << 1;
+
+            int pos0 = EnsureReadCapacityAndShift(cnt0);
+
+            fixed (byte* data0 = Data)
+            {
+                return ReadCharArray0(cnt, data0 + pos0, cnt0);
+            }
+        }
+
+        /** <inheritdoc /> */
+        public override void WriteInt(int val)
+        {
+            int pos0 = EnsureWriteCapacityAndShift(4);
+
+            fixed (byte* data0 = Data)
+            {
+                WriteInt0(val, data0 + pos0);
+            }
+        }
+
+        /** <inheritdoc /> */
+        public override void WriteInt(int writePos, int val)
+        {
+            EnsureWriteCapacity(writePos + 4);
+
+            fixed (byte* data0 = Data)
+            {
+                WriteInt0(val, data0 + writePos);
+            }
+        }
+
+        /** <inheritdoc /> */
+        public override int ReadInt()
+        {
+            int pos0 = EnsureReadCapacityAndShift(4);
+
+            fixed (byte* data0 = Data)
+            {
+                return ReadInt0(data0 + pos0);
+            }
+        }
+
+        /** <inheritdoc /> */
+        public override void WriteIntArray(int[] val)
+        {
+            int cnt = val.Length << 2;
+
+            int pos0 = EnsureWriteCapacityAndShift(cnt);
+
+            fixed (byte* data0 = Data)
+            {
+                WriteIntArray0(val, data0 + pos0, cnt);
+            }
+        }
+
+        /** <inheritdoc /> */
+        public override int[] ReadIntArray(int cnt)
+        {
+            int cnt0 = cnt << 2;
+
+            int pos0 = EnsureReadCapacityAndShift(cnt0);
+
+            fixed (byte* data0 = Data)
+            {
+                return ReadIntArray0(cnt, data0 + pos0, cnt0);
+            }
+        }
+
+        /** <inheritdoc /> */
+        public override void WriteFloatArray(float[] val)
+        {
+            int cnt = val.Length << 2;
+
+            int pos0 = EnsureWriteCapacityAndShift(cnt);
+
+            fixed (byte* data0 = Data)
+            {
+                WriteFloatArray0(val, data0 + pos0, cnt);
+            }
+        }
+
+        /** <inheritdoc /> */
+        public override float[] ReadFloatArray(int cnt)
+        {
+            int cnt0 = cnt << 2;
+
+            int pos0 = EnsureReadCapacityAndShift(cnt0);
+
+            fixed (byte* data0 = Data)
+            {
+                return ReadFloatArray0(cnt, data0 + pos0, cnt0);
+            }
+        }
+
+        /** <inheritdoc /> */
+        public override void WriteLong(long val)
+        {
+            int pos0 = EnsureWriteCapacityAndShift(8);
+
+            fixed (byte* data0 = Data)
+            {
+                WriteLong0(val, data0 + pos0);
+            }
+        }
+
+        /** <inheritdoc /> */
+        public override long ReadLong()
+        {
+            int pos0 = EnsureReadCapacityAndShift(8);
+
+            fixed (byte* data0 = Data)
+            {
+                return ReadLong0(data0 + pos0);
+            }
+        }
+
+        /** <inheritdoc /> */
+        public override void WriteLongArray(long[] val)
+        {
+            int cnt = val.Length << 3;
+
+            int pos0 = EnsureWriteCapacityAndShift(cnt);
+
+            fixed (byte* data0 = Data)
+            {
+                WriteLongArray0(val, data0 + pos0, cnt);
+            }
+        }
+
+        /** <inheritdoc /> */
+        public override long[] ReadLongArray(int cnt)
+        {
+            int cnt0 = cnt << 3;
+
+            int pos0 = EnsureReadCapacityAndShift(cnt0);
+
+            fixed (byte* data0 = Data)
+            {
+                return ReadLongArray0(cnt, data0 + pos0, cnt0);
+            }
+        }
+
+        /** <inheritdoc /> */
+        public override void WriteDoubleArray(double[] val)
+        {
+            int cnt = val.Length << 3;
+
+            int pos0 = EnsureWriteCapacityAndShift(cnt);
+
+            fixed (byte* data0 = Data)
+            {
+                WriteDoubleArray0(val, data0 + pos0, cnt);
+            }
+        }
+
+        /** <inheritdoc /> */
+        public override double[] ReadDoubleArray(int cnt)
+        {
+            int cnt0 = cnt << 3;
+
+            int pos0 = EnsureReadCapacityAndShift(cnt0);
+
+            fixed (byte* data0 = Data)
+            {
+                return ReadDoubleArray0(cnt, data0 + pos0, cnt0);
+            }
+        }
+
+        /** <inheritdoc /> */
+        public override int WriteString(char* chars, int charCnt, int byteCnt, Encoding encoding)
+        {
+            int pos0 = EnsureWriteCapacityAndShift(byteCnt);
+
+            int written;
+
+            fixed (byte* data0 = Data)
+            {
+                written = WriteString0(chars, charCnt, byteCnt, encoding, data0 + pos0);
+            }
+
+            return written;
+        }
+
+        /** <inheritdoc /> */
+        public override void Write(byte* src, int cnt)
+        {
+            EnsureWriteCapacity(Pos + cnt);
+
+            fixed (byte* data0 = Data)
+            {
+                WriteInternal(src, cnt, data0);
+            }
+
+            ShiftWrite(cnt);
+        }
+
+        /** <inheritdoc /> */
+        public override void Read(byte* dest, int cnt)
+        {
+            fixed (byte* data0 = Data)
+            {
+                ReadInternal(dest, cnt, data0);
+            }
+        }
+
+        /** <inheritdoc /> */
+        public override int Remaining()
+        {
+            return Data.Length - Pos;
+        }
+
+        /** <inheritdoc /> */
+        public override byte[] Array()
+        {
+            return Data;
+        }
+
+        /** <inheritdoc /> */
+        public override byte[] ArrayCopy()
+        {
+            byte[] copy = new byte[Pos];
+
+            Buffer.BlockCopy(Data, 0, copy, 0, Pos);
+
+            return copy;
+        }
+
+        /** <inheritdoc /> */
+        public override bool IsSameArray(byte[] arr)
+        {
+            return Data == arr;
+        }
+
+        /** <inheritdoc /> */
+        protected override void Dispose(bool disposing)
+        {
+            // No-op.
+        }
+
+        /// <summary>
+        /// Internal array.
+        /// </summary>
+        internal byte[] InternalArray
+        {
+            get { return Data; }
+        }
+
+        /** <inheritdoc /> */
+        protected override void EnsureWriteCapacity(int cnt)
+        {
+            if (cnt > Data.Length)
+            {
+                int newCap = Capacity(Data.Length, cnt);
+
+                byte[] data0 = new byte[newCap];
+
+                // Copy the whole initial array length here because it can be changed
+                // from Java without position adjusting.
+                Buffer.BlockCopy(Data, 0, data0, 0, Data.Length);
+
+                Data = data0;
+            }
+        }
+
+        /** <inheritdoc /> */
+        protected override void EnsureReadCapacity(int cnt)
+        {
+            if (Data.Length - Pos < cnt)
+                throw new EndOfStreamException("Not enough data in stream [expected=" + cnt +
+                    ", remaining=" + (Data.Length - Pos) + ']');
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/f2eb16cd/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Io/PortableStreamAdapter.cs
----------------------------------------------------------------------
diff --git a/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Io/PortableStreamAdapter.cs b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Io/PortableStreamAdapter.cs
new file mode 100644
index 0000000..1d17f89
--- /dev/null
+++ b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Io/PortableStreamAdapter.cs
@@ -0,0 +1,114 @@
+/*
+ * 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.Impl.Portable.IO
+{
+    using System;
+    using System.IO;
+
+    /// <summary>
+    /// Adapter providing .Net streaming functionality over the portable stream.
+    /// </summary>
+    internal class PortableStreamAdapter : Stream
+    {
+        /// <summary>
+        /// 
+        /// </summary>
+        private readonly IPortableStream _stream;
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        /// <param name="stream">Stream.</param>
+        public PortableStreamAdapter(IPortableStream stream)
+        {
+            _stream = stream;
+        }
+
+        /** <inheritDoc /> */
+        public override void Write(byte[] buffer, int offset, int count)
+        {
+            _stream.Write(buffer, offset, count);
+        }
+
+        /** <inheritDoc /> */
+        public override int Read(byte[] buffer, int offset, int count)
+        {
+            _stream.Read(buffer, offset, count);
+
+            return count;
+        }
+
+        /** <inheritDoc /> */
+        public override void Flush()
+        {
+            // No-op.
+        }
+
+        /** <inheritDoc /> */
+        public override bool CanRead
+        {
+            get { return true; }
+        }
+
+        /** <inheritDoc /> */
+        public override bool CanWrite
+        {
+            get { return true; }
+        }
+
+        /** <inheritDoc /> */
+        public override bool CanSeek
+        {
+            get { return false; }
+        }
+
+        /** <inheritDoc /> */
+        public override long Seek(long offset, SeekOrigin origin)
+        {
+            throw new NotSupportedException("Stream is not seekable.");
+        }
+
+        /** <inheritDoc /> */
+        public override long Position
+        {
+            get
+            {
+                throw new NotSupportedException("Stream is not seekable.");
+            }
+            set
+            {
+                throw new NotSupportedException("Stream is not seekable.");
+            }
+        }
+
+        /** <inheritDoc /> */
+        public override long Length
+        {
+            get 
+            {
+                throw new NotSupportedException("Stream is not seekable.");
+            }
+        }
+
+        /** <inheritDoc /> */
+        public override void SetLength(long value)
+        {
+            throw new NotSupportedException("Stream is not seekable.");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/f2eb16cd/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/IPortableMetadataHandler.cs
----------------------------------------------------------------------
diff --git a/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/IPortableMetadataHandler.cs b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/IPortableMetadataHandler.cs
new file mode 100644
index 0000000..dc3090f
--- /dev/null
+++ b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/IPortableMetadataHandler.cs
@@ -0,0 +1,41 @@
+/*
+ * 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.Impl.Portable.Metadata
+{
+    using System.Collections.Generic;
+
+    /// <summary>
+    /// Portable metadata handler.
+    /// </summary>
+    public interface IPortableMetadataHandler
+    {
+        /// <summary>
+        /// Callback invoked when named field is written.
+        /// </summary>
+        /// <param name="fieldId">Field ID.</param>
+        /// <param name="fieldName">Field name.</param>
+        /// <param name="typeId">Field type ID.</param>
+        void OnFieldWrite(int fieldId, string fieldName, int typeId);
+
+        /// <summary>
+        /// Callback invoked when object write is finished and it is time to collect missing metadata.
+        /// </summary>
+        /// <returns>Collected metadata.</returns>
+        IDictionary<string, int> OnObjectWriteFinished();
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/f2eb16cd/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/PortableHashsetMetadataHandler.cs
----------------------------------------------------------------------
diff --git a/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/PortableHashsetMetadataHandler.cs b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/PortableHashsetMetadataHandler.cs
new file mode 100644
index 0000000..8df5f36
--- /dev/null
+++ b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/PortableHashsetMetadataHandler.cs
@@ -0,0 +1,69 @@
+/*
+ * 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.Impl.Portable.Metadata
+{
+    using System.Collections.Generic;
+
+    /// <summary>
+    /// Metadata handler which uses hash set to determine whether field was already written or not.
+    /// </summary>
+    internal class PortableHashsetMetadataHandler : IPortableMetadataHandler
+    {
+        /** Empty fields collection. */
+        private static readonly IDictionary<string, int> EmptyFields = new Dictionary<string, int>();
+
+        /** IDs known when serialization starts. */
+        private readonly ICollection<int> _ids;
+
+        /** New fields. */
+        private IDictionary<string, int> _fieldMap;
+
+        /** */
+        private readonly bool _newType;
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        /// <param name="ids">IDs.</param>
+        /// <param name="newType">True is metadata for type is not saved.</param>
+        public PortableHashsetMetadataHandler(ICollection<int> ids, bool newType)
+        {
+            _ids = ids;
+            _newType = newType;
+        }
+
+        /** <inheritdoc /> */
+        public void OnFieldWrite(int fieldId, string fieldName, int typeId)
+        {
+            if (!_ids.Contains(fieldId))
+            {
+                if (_fieldMap == null)
+                    _fieldMap = new Dictionary<string, int>();
+
+                if (!_fieldMap.ContainsKey(fieldName))
+                    _fieldMap[fieldName] = typeId;
+            }
+        }
+
+        /** <inheritdoc /> */
+        public IDictionary<string, int> OnObjectWriteFinished()
+        {
+            return _fieldMap ?? (_newType ? EmptyFields : null);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/f2eb16cd/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/PortableMetadataHolder.cs
----------------------------------------------------------------------
diff --git a/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/PortableMetadataHolder.cs b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/PortableMetadataHolder.cs
new file mode 100644
index 0000000..a3fa90f
--- /dev/null
+++ b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/PortableMetadataHolder.cs
@@ -0,0 +1,149 @@
+/*
+ * 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.Impl.Portable.Metadata
+{
+    using System;
+    using System.Collections.Generic;
+    using Apache.Ignite.Core.Portable;
+
+    /// <summary>
+    /// Metadata for particular type.
+    /// </summary>
+    internal class PortableMetadataHolder
+    {
+        /** Type ID. */
+        private readonly int _typeId;
+
+        /** Type name. */
+        private readonly string _typeName;
+
+        /** Affinity key field name. */
+        private readonly string _affKeyFieldName;
+
+        /** Empty metadata when nothig is know about object fields yet. */
+        private readonly IPortableMetadata _emptyMeta;
+
+        /** Collection of know field IDs. */
+        private volatile ICollection<int> _ids;
+
+        /** Last known unmodifiable metadata which is given to the user. */
+        private volatile PortableMetadataImpl _meta;
+
+        /** Saved flag (set if type metadata was saved at least once). */
+        private volatile bool _saved;
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        /// <param name="typeId">Type ID.</param>
+        /// <param name="typeName">Type name.</param>
+        /// <param name="affKeyFieldName">Affinity key field name.</param>
+        public PortableMetadataHolder(int typeId, string typeName, string affKeyFieldName)
+        {
+            _typeId = typeId;
+            _typeName = typeName;
+            _affKeyFieldName = affKeyFieldName;
+
+            _emptyMeta = new PortableMetadataImpl(typeId, typeName, null, affKeyFieldName);
+        }
+
+        /// <summary>
+        /// Get saved flag.
+        /// </summary>
+        /// <returns>True if type metadata was saved at least once.</returns>
+        public bool Saved()
+        {
+            return _saved;
+        }
+
+        /// <summary>
+        /// Get current type metadata.
+        /// </summary>
+        /// <returns>Type metadata.</returns>
+        public IPortableMetadata Metadata()
+        {
+            PortableMetadataImpl meta0 = _meta;
+
+            return meta0 != null ? _meta : _emptyMeta;
+        }
+
+        /// <summary>
+        /// Currently cached field IDs.
+        /// </summary>
+        /// <returns>Cached field IDs.</returns>
+        public ICollection<int> FieldIds()
+        {
+            ICollection<int> ids0 = _ids;
+
+            if (_ids == null)
+            {
+                lock (this)
+                {
+                    ids0 = _ids;
+
+                    if (ids0 == null)
+                    {
+                        ids0 = new HashSet<int>();
+
+                        _ids = ids0;
+                    }
+                }
+            }
+
+            return ids0;
+        }
+
+        /// <summary>
+        /// Merge newly sent field metadatas into existing ones.
+        /// </summary>
+        /// <param name="newMap">New field metadatas map.</param>
+        public void Merge(IDictionary<int, Tuple<string, int>> newMap)
+        {
+            _saved = true;
+
+            if (newMap == null || newMap.Count == 0)
+                return;
+
+            lock (this)
+            {
+                // 1. Create copies of the old meta.
+                ICollection<int> ids0 = _ids;
+                PortableMetadataImpl meta0 = _meta;
+
+                ICollection<int> newIds = ids0 != null ? new HashSet<int>(ids0) : new HashSet<int>();
+
+                IDictionary<string, int> newFields = meta0 != null ?
+                    new Dictionary<string, int>(meta0.FieldsMap()) : new Dictionary<string, int>(newMap.Count);
+
+                // 2. Add new fields.
+                foreach (KeyValuePair<int, Tuple<string, int>> newEntry in newMap)
+                {
+                    if (!newIds.Contains(newEntry.Key))
+                        newIds.Add(newEntry.Key);
+
+                    if (!newFields.ContainsKey(newEntry.Value.Item1))
+                        newFields[newEntry.Value.Item1] = newEntry.Value.Item2;
+                }
+
+                // 3. Assign new meta. Order is important here: meta must be assigned before field IDs.
+                _meta = new PortableMetadataImpl(_typeId, _typeName, newFields, _affKeyFieldName);
+                _ids = newIds;
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/f2eb16cd/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/PortableMetadataImpl.cs
----------------------------------------------------------------------
diff --git a/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/PortableMetadataImpl.cs b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/PortableMetadataImpl.cs
new file mode 100644
index 0000000..06578c0
--- /dev/null
+++ b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/PortableMetadataImpl.cs
@@ -0,0 +1,200 @@
+/*
+ * 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.Impl.Portable.Metadata
+{
+    using System.Collections.Generic;
+    using System.Diagnostics.CodeAnalysis;
+    using Apache.Ignite.Core.Portable;
+
+    /// <summary>
+    /// Portable metadata implementation.
+    /// </summary>
+    internal class PortableMetadataImpl : IPortableMetadata
+    {
+        /** Empty metadata. */
+        [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
+        public static readonly PortableMetadataImpl EmptyMeta =
+            new PortableMetadataImpl(PortableUtils.TypeObject, PortableTypeNames.TypeNameObject, null, null);
+
+        /** Empty dictionary. */
+        private static readonly IDictionary<string, int> EmptyDict = new Dictionary<string, int>();
+
+        /** Empty list. */
+        private static readonly ICollection<string> EmptyList = new List<string>().AsReadOnly();
+
+        /** Fields. */
+        private readonly IDictionary<string, int> _fields;
+
+        /// <summary>
+        /// Get type name by type ID.
+        /// </summary>
+        /// <param name="typeId">Type ID.</param>
+        /// <returns>Type name.</returns>
+        private static string ConvertTypeName(int typeId)
+        {
+            switch (typeId)
+            {
+                case PortableUtils.TypeBool:
+                    return PortableTypeNames.TypeNameBool;
+                case PortableUtils.TypeByte:
+                    return PortableTypeNames.TypeNameByte;
+                case PortableUtils.TypeShort:
+                    return PortableTypeNames.TypeNameShort;
+                case PortableUtils.TypeChar:
+                    return PortableTypeNames.TypeNameChar;
+                case PortableUtils.TypeInt:
+                    return PortableTypeNames.TypeNameInt;
+                case PortableUtils.TypeLong:
+                    return PortableTypeNames.TypeNameLong;
+                case PortableUtils.TypeFloat:
+                    return PortableTypeNames.TypeNameFloat;
+                case PortableUtils.TypeDouble:
+                    return PortableTypeNames.TypeNameDouble;
+                case PortableUtils.TypeDecimal:
+                    return PortableTypeNames.TypeNameDecimal;
+                case PortableUtils.TypeString:
+                    return PortableTypeNames.TypeNameString;
+                case PortableUtils.TypeGuid:
+                    return PortableTypeNames.TypeNameGuid;
+                case PortableUtils.TypeDate:
+                    return PortableTypeNames.TypeNameDate;
+                case PortableUtils.TypeEnum:
+                    return PortableTypeNames.TypeNameEnum;
+                case PortableUtils.TypePortable:
+                case PortableUtils.TypeObject:
+                    return PortableTypeNames.TypeNameObject;
+                case PortableUtils.TypeArrayBool:
+                    return PortableTypeNames.TypeNameArrayBool;
+                case PortableUtils.TypeArrayByte:
+                    return PortableTypeNames.TypeNameArrayByte;
+                case PortableUtils.TypeArrayShort:
+                    return PortableTypeNames.TypeNameArrayShort;
+                case PortableUtils.TypeArrayChar:
+                    return PortableTypeNames.TypeNameArrayChar;
+                case PortableUtils.TypeArrayInt:
+                    return PortableTypeNames.TypeNameArrayInt;
+                case PortableUtils.TypeArrayLong:
+                    return PortableTypeNames.TypeNameArrayLong;
+                case PortableUtils.TypeArrayFloat:
+                    return PortableTypeNames.TypeNameArrayFloat;
+                case PortableUtils.TypeArrayDouble:
+                    return PortableTypeNames.TypeNameArrayDouble;
+                case PortableUtils.TypeArrayDecimal:
+                    return PortableTypeNames.TypeNameArrayDecimal;
+                case PortableUtils.TypeArrayString:
+                    return PortableTypeNames.TypeNameArrayString;
+                case PortableUtils.TypeArrayGuid:
+                    return PortableTypeNames.TypeNameArrayGuid;
+                case PortableUtils.TypeArrayDate:
+                    return PortableTypeNames.TypeNameArrayDate;
+                case PortableUtils.TypeArrayEnum:
+                    return PortableTypeNames.TypeNameArrayEnum;
+                case PortableUtils.TypeArray:
+                    return PortableTypeNames.TypeNameArrayObject;
+                case PortableUtils.TypeCollection:
+                    return PortableTypeNames.TypeNameCollection;
+                case PortableUtils.TypeDictionary:
+                    return PortableTypeNames.TypeNameMap;
+                default:
+                    throw new PortableException("Invalid type ID: " + typeId);
+            }
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="PortableMetadataImpl" /> class.
+        /// </summary>
+        /// <param name="reader">The reader.</param>
+        public PortableMetadataImpl(IPortableRawReader reader)
+        {
+            TypeId = reader.ReadInt();
+            TypeName = reader.ReadString();
+            AffinityKeyFieldName = reader.ReadString();
+            _fields = reader.ReadGenericDictionary<string, int>();
+        }
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        /// <param name="typeId">Type ID.</param>
+        /// <param name="typeName">Type name.</param>
+        /// <param name="fields">Fields.</param>
+        /// <param name="affKeyFieldName">Affinity key field name.</param>
+        public PortableMetadataImpl(int typeId, string typeName, IDictionary<string, int> fields,
+            string affKeyFieldName)
+        {
+            TypeId = typeId;
+            TypeName = typeName;
+            AffinityKeyFieldName = affKeyFieldName;
+            _fields = fields;
+        }
+
+        /// <summary>
+        /// Type ID.
+        /// </summary>
+        /// <returns></returns>
+        public int TypeId { get; private set; }
+
+        /// <summary>
+        /// Gets type name.
+        /// </summary>
+        public string TypeName { get; private set; }
+
+        /// <summary>
+        /// Gets field names for that type.
+        /// </summary>
+        public ICollection<string> Fields
+        {
+            get { return _fields != null ? _fields.Keys : EmptyList; }
+        }
+
+        /// <summary>
+        /// Gets field type for the given field name.
+        /// </summary>
+        /// <param name="fieldName">Field name.</param>
+        /// <returns>
+        /// Field type.
+        /// </returns>
+        public string GetFieldTypeName(string fieldName)
+        {
+            if (_fields != null)
+            {
+                int typeId;
+
+                _fields.TryGetValue(fieldName, out typeId);
+
+                return ConvertTypeName(typeId);
+            }
+            
+            return null;
+        }
+
+        /// <summary>
+        /// Gets optional affinity key field name.
+        /// </summary>
+        public string AffinityKeyFieldName { get; private set; }
+
+        /// <summary>
+        /// Gets fields map.
+        /// </summary>
+        /// <returns>Fields map.</returns>
+        public IDictionary<string, int> FieldsMap()
+        {
+            return _fields ?? EmptyDict;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/f2eb16cd/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderField.cs
----------------------------------------------------------------------
diff --git a/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderField.cs b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderField.cs
new file mode 100644
index 0000000..026d0d4
--- /dev/null
+++ b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderField.cs
@@ -0,0 +1,73 @@
+/*
+ * 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.Impl.Portable
+{
+    using System;
+
+    /// <summary>
+    /// Portable builder field.
+    /// </summary>
+    internal class PortableBuilderField
+    {
+        /** Remove marker object. */
+        public static readonly object RmvMarkerObj = new object();
+
+        /** Remove marker. */
+        public static readonly PortableBuilderField RmvMarker = 
+            new PortableBuilderField(null, RmvMarkerObj);
+
+        /** Type. */
+        private readonly Type _typ;
+
+        /** Value. */
+        private readonly object _val;
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        /// <param name="typ">Type.</param>
+        /// <param name="val">Value.</param>
+        public PortableBuilderField(Type typ, object val)
+        {
+            _typ = typ;
+            _val = val;
+        }
+
+        /// <summary>
+        /// Type.
+        /// </summary>
+        public Type Type
+        {
+            get
+            {
+                return _typ;
+            }
+        }
+
+        /// <summary>
+        /// Value.
+        /// </summary>
+        public object Value
+        {
+            get
+            {
+                return _val;
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/f2eb16cd/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderImpl.cs
----------------------------------------------------------------------
diff --git a/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderImpl.cs b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderImpl.cs
new file mode 100644
index 0000000..dc0f570
--- /dev/null
+++ b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderImpl.cs
@@ -0,0 +1,923 @@
+/*
+ * 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.Impl.Portable
+{
+    using System;
+    using System.Collections.Generic;
+    using System.IO;
+    using Apache.Ignite.Core.Common;
+    using Apache.Ignite.Core.Impl.Portable.IO;
+    using Apache.Ignite.Core.Impl.Portable.Metadata;
+    using Apache.Ignite.Core.Portable;
+
+    /// <summary>
+    /// Portable builder implementation.
+    /// </summary>
+    internal class PortableBuilderImpl : IPortableBuilder
+    {
+        /** Type IDs for metadata. */
+        private static readonly IDictionary<Type, int> TypeIds;
+
+        /** Cached dictionary with no values. */
+        private static readonly IDictionary<int, object> EmptyVals = new Dictionary<int, object>();
+
+        /** Offset: length. */
+        private const int OffsetLen = 10;
+
+        /** Portables. */
+        private readonly PortablesImpl _portables;
+
+        /** */
+        private readonly PortableBuilderImpl _parent;
+
+        /** Initial portable object. */
+        private readonly PortableUserObject _obj;
+
+        /** Type descriptor. */
+        private readonly IPortableTypeDescriptor _desc;
+
+        /** Values. */
+        private IDictionary<string, PortableBuilderField> _vals;
+
+        /** Contextual fields. */
+        private IDictionary<int, object> _cache;
+
+        /** Hash code. */
+        private int _hashCode;
+        
+        /** Current context. */
+        private Context _ctx;
+        
+        /// <summary>
+        /// Static initializer.
+        /// </summary>
+        static PortableBuilderImpl()
+        {
+            TypeIds = new Dictionary<Type, int>();
+
+            // 1. Primitives.
+            TypeIds[typeof(byte)] = PortableUtils.TypeByte;
+            TypeIds[typeof(bool)] = PortableUtils.TypeBool;
+            TypeIds[typeof(short)] = PortableUtils.TypeShort;
+            TypeIds[typeof(char)] = PortableUtils.TypeChar;
+            TypeIds[typeof(int)] = PortableUtils.TypeInt;
+            TypeIds[typeof(long)] = PortableUtils.TypeLong;
+            TypeIds[typeof(float)] = PortableUtils.TypeFloat;
+            TypeIds[typeof(double)] = PortableUtils.TypeDouble;
+            TypeIds[typeof(decimal)] = PortableUtils.TypeDecimal;
+
+            TypeIds[typeof(byte[])] = PortableUtils.TypeArrayByte;
+            TypeIds[typeof(bool[])] = PortableUtils.TypeArrayBool;
+            TypeIds[typeof(short[])] = PortableUtils.TypeArrayShort;
+            TypeIds[typeof(char[])] = PortableUtils.TypeArrayChar;
+            TypeIds[typeof(int[])] = PortableUtils.TypeArrayInt;
+            TypeIds[typeof(long[])] = PortableUtils.TypeArrayLong;
+            TypeIds[typeof(float[])] = PortableUtils.TypeArrayFloat;
+            TypeIds[typeof(double[])] = PortableUtils.TypeArrayDouble;
+            TypeIds[typeof(decimal[])] = PortableUtils.TypeArrayDecimal;
+
+            // 2. String.
+            TypeIds[typeof(string)] = PortableUtils.TypeString;
+            TypeIds[typeof(string[])] = PortableUtils.TypeArrayString;
+
+            // 3. Guid.
+            TypeIds[typeof(Guid)] = PortableUtils.TypeGuid;
+            TypeIds[typeof(Guid?)] = PortableUtils.TypeGuid;
+            TypeIds[typeof(Guid[])] = PortableUtils.TypeArrayGuid;
+            TypeIds[typeof(Guid?[])] = PortableUtils.TypeArrayGuid;
+
+            // 4. Date.
+            TypeIds[typeof(DateTime)] = PortableUtils.TypeDate;
+            TypeIds[typeof(DateTime?)] = PortableUtils.TypeDate;
+            TypeIds[typeof(DateTime[])] = PortableUtils.TypeArrayDate;
+            TypeIds[typeof(DateTime?[])] = PortableUtils.TypeArrayDate;
+        }
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        /// <param name="portables">Portables.</param>
+        /// <param name="obj">Initial portable object.</param>
+        /// <param name="desc">Type descriptor.</param>
+        public PortableBuilderImpl(PortablesImpl portables, PortableUserObject obj,
+            IPortableTypeDescriptor desc) : this(portables, null, obj, desc) 
+        { 
+            // No-op.
+        }
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        /// <param name="portables">Portables.</param>
+        /// <param name="parent">Parent builder.</param>
+        /// <param name="obj">Initial portable object.</param>
+        /// <param name="desc">Type descriptor.</param>
+        public PortableBuilderImpl(PortablesImpl portables, PortableBuilderImpl parent, 
+            PortableUserObject obj, IPortableTypeDescriptor desc)
+        {
+            _portables = portables;
+            _parent = parent ?? this;
+            _obj = obj;
+            _desc = desc;
+
+            _hashCode = obj.GetHashCode();
+        }
+
+        /** <inheritDoc /> */
+        public IPortableBuilder SetHashCode(int hashCode)
+        {
+            _hashCode = hashCode;
+
+            return this;
+        }
+
+        /** <inheritDoc /> */
+        public T GetField<T>(string name)
+        {
+            PortableBuilderField field;
+
+            if (_vals != null && _vals.TryGetValue(name, out field))
+                return field != PortableBuilderField.RmvMarker ? (T)field.Value : default(T);
+            T val = _obj.Field<T>(name, this);
+
+            if (_vals == null)
+                _vals = new Dictionary<string, PortableBuilderField>(2);
+
+            _vals[name] = new PortableBuilderField(typeof(T), val);
+
+            return val;
+        }
+
+        /** <inheritDoc /> */
+        public IPortableBuilder SetField<T>(string name, T val)
+        {
+            return SetField0(name, new PortableBuilderField(typeof(T), val));
+        }
+
+        /** <inheritDoc /> */
+        public IPortableBuilder RemoveField(string name)
+        {
+            return SetField0(name, PortableBuilderField.RmvMarker);
+        }
+
+        /** <inheritDoc /> */
+        public IPortableObject Build()
+        {
+            PortableHeapStream inStream = new PortableHeapStream(_obj.Data);
+
+            inStream.Seek(_obj.Offset, SeekOrigin.Begin);
+
+            // Assume that resulting length will be no less than header + [fields_cnt] * 12;
+            int len = PortableUtils.FullHdrLen + (_vals == null ? 0 : _vals.Count * 12);
+
+            PortableHeapStream outStream = new PortableHeapStream(len);
+
+            PortableWriterImpl writer = _portables.Marshaller.StartMarshal(outStream);
+
+            writer.Builder(this);
+
+            // All related builders will work in this context with this writer.
+            _parent._ctx = new Context(writer);
+            
+            try
+            {
+                // Write.
+                writer.Write(this, null);
+                
+                // Process metadata.
+                _portables.Marshaller.FinishMarshal(writer);
+
+                // Create portable object once metadata is processed.
+                return new PortableUserObject(_portables.Marshaller, outStream.InternalArray, 0,
+                    _desc.TypeId, _hashCode);
+            }
+            finally
+            {
+                // Cleanup.
+                _parent._ctx.Closed = true;
+            }
+        }
+
+        /// <summary>
+        /// Create child builder.
+        /// </summary>
+        /// <param name="obj">Portable object.</param>
+        /// <returns>Child builder.</returns>
+        public PortableBuilderImpl Child(PortableUserObject obj)
+        {
+            return _portables.ChildBuilder(_parent, obj);
+        }
+        
+        /// <summary>
+        /// Get cache field.
+        /// </summary>
+        /// <param name="pos">Position.</param>
+        /// <param name="val">Value.</param>
+        /// <returns><c>true</c> if value is found in cache.</returns>
+        public bool CachedField<T>(int pos, out T val)
+        {
+            if (_parent._cache != null)
+            {
+                object res;
+
+                if (_parent._cache.TryGetValue(pos, out res))
+                {
+                    val = res != null ? (T)res : default(T);
+
+                    return true;
+                }
+            }
+
+            val = default(T);
+
+            return false;
+        }
+
+        /// <summary>
+        /// Add field to cache test.
+        /// </summary>
+        /// <param name="pos">Position.</param>
+        /// <param name="val">Value.</param>
+        public void CacheField(int pos, object val)
+        {
+            if (_parent._cache == null)
+                _parent._cache = new Dictionary<int, object>(2);
+
+            _parent._cache[pos] = val;
+        }
+
+        /// <summary>
+        /// Internal set field routine.
+        /// </summary>
+        /// <param name="fieldName">Name.</param>
+        /// <param name="val">Value.</param>
+        /// <returns>This builder.</returns>
+        private IPortableBuilder SetField0(string fieldName, PortableBuilderField val)
+        {
+            if (_vals == null)
+                _vals = new Dictionary<string, PortableBuilderField>();
+
+            _vals[fieldName] = val;
+
+            return this;
+        }
+
+        /// <summary>
+        /// Mutate portable object.
+        /// </summary>
+        /// <param name="inStream">Input stream with initial object.</param>
+        /// <param name="outStream">Output stream.</param>
+        /// <param name="desc">Portable type descriptor.</param>
+        /// <param name="hashCode">Hash code.</param>
+        /// <param name="vals">Values.</param>
+        internal void Mutate(
+            PortableHeapStream inStream,
+            PortableHeapStream outStream,
+            IPortableTypeDescriptor desc,
+            int hashCode, 
+            IDictionary<string, PortableBuilderField> vals)
+        {
+            // Set correct builder to writer frame.
+            PortableBuilderImpl oldBuilder = _parent._ctx.Writer.Builder(_parent);
+
+            int streamPos = inStream.Position;
+            
+            try
+            {
+                // Prepare fields.
+                IPortableMetadataHandler metaHnd = _portables.Marshaller.MetadataHandler(desc);
+
+                IDictionary<int, object> vals0;
+
+                if (vals == null || vals.Count == 0)
+                    vals0 = EmptyVals;
+                else
+                {
+                    vals0 = new Dictionary<int, object>(vals.Count);
+
+                    foreach (KeyValuePair<string, PortableBuilderField> valEntry in vals)
+                    {
+                        int fieldId = PortableUtils.FieldId(desc.TypeId, valEntry.Key, desc.NameConverter, desc.Mapper);
+
+                        if (vals0.ContainsKey(fieldId))
+                            throw new IgniteException("Collision in field ID detected (change field name or " +
+                                "define custom ID mapper) [fieldName=" + valEntry.Key + ", fieldId=" + fieldId + ']');
+
+                        vals0[fieldId] = valEntry.Value.Value;
+
+                        // Write metadata if: 1) it is enabled for type; 2) type is not null (i.e. it is neither 
+                        // remove marker, nor a field read through "GetField" method.
+                        if (metaHnd != null && valEntry.Value.Type != null)
+                            metaHnd.OnFieldWrite(fieldId, valEntry.Key, TypeId(valEntry.Value.Type));
+                    }
+                }
+
+                // Actual processing.
+                Mutate0(_parent._ctx, inStream, outStream, true, hashCode, vals0);
+
+                // 3. Handle metadata.
+                if (metaHnd != null)
+                {
+                    IDictionary<string, int> meta = metaHnd.OnObjectWriteFinished();
+
+                    if (meta != null)
+                        _parent._ctx.Writer.SaveMetadata(desc.TypeId, desc.TypeName, desc.AffinityKeyFieldName, meta);
+                }
+            }
+            finally
+            {
+                // Restore builder frame.
+                _parent._ctx.Writer.Builder(oldBuilder);
+
+                inStream.Seek(streamPos, SeekOrigin.Begin);
+            }
+        }
+
+        /// <summary>
+        /// Internal mutation routine.
+        /// </summary>
+        /// <param name="inStream">Input stream.</param>
+        /// <param name="outStream">Output stream.</param>
+        /// <param name="ctx">Context.</param>
+        /// <param name="changeHash">WHether hash should be changed.</param>
+        /// <param name="hash">New hash.</param>
+        /// <param name="vals">Values to be replaced.</param>
+        /// <returns>Mutated object.</returns>
+        private void Mutate0(Context ctx, PortableHeapStream inStream, IPortableStream outStream,
+            bool changeHash, int hash, IDictionary<int, object> vals)
+        {
+            int inStartPos = inStream.Position;
+            int outStartPos = outStream.Position;
+
+            byte inHdr = inStream.ReadByte();
+
+            if (inHdr == PortableUtils.HdrNull)
+                outStream.WriteByte(PortableUtils.HdrNull);
+            else if (inHdr == PortableUtils.HdrHnd)
+            {
+                int inHnd = inStream.ReadInt();
+
+                int oldPos = inStartPos - inHnd;
+                int newPos;
+
+                if (ctx.OldToNew(oldPos, out newPos))
+                {
+                    // Handle is still valid.
+                    outStream.WriteByte(PortableUtils.HdrHnd);
+                    outStream.WriteInt(outStartPos - newPos);
+                }
+                else
+                {
+                    // Handle is invalid, write full object.
+                    int inRetPos = inStream.Position;
+
+                    inStream.Seek(oldPos, SeekOrigin.Begin);
+
+                    Mutate0(ctx, inStream, outStream, false, 0, EmptyVals);
+
+                    inStream.Seek(inRetPos, SeekOrigin.Begin);
+                }
+            }
+            else if (inHdr == PortableUtils.HdrFull)
+            {
+                byte inUsrFlag = inStream.ReadByte();
+                int inTypeId = inStream.ReadInt();
+                int inHash = inStream.ReadInt();
+                int inLen = inStream.ReadInt();
+                int inRawOff = inStream.ReadInt();
+
+                int hndPos;
+
+                if (ctx.AddOldToNew(inStartPos, outStartPos, out hndPos))
+                {
+                    // Object could be cached in parent builder.
+                    object cachedVal;
+
+                    if (_parent._cache != null && _parent._cache.TryGetValue(inStartPos, out cachedVal)) {
+                        ctx.Writer.Write(cachedVal, null);
+                    }
+                    else
+                    {
+                        // New object, write in full form.
+                        outStream.WriteByte(PortableUtils.HdrFull);
+                        outStream.WriteByte(inUsrFlag);
+                        outStream.WriteInt(inTypeId);
+                        outStream.WriteInt(changeHash ? hash : inHash);
+
+                        // Skip length and raw offset as they are not known at this point.
+                        outStream.Seek(8, SeekOrigin.Current);
+
+                        // Write regular fields.
+                        while (inStream.Position < inStartPos + inRawOff)
+                        {
+                            int inFieldId = inStream.ReadInt();
+                            int inFieldLen = inStream.ReadInt();
+                            int inFieldDataPos = inStream.Position;
+
+                            object fieldVal;
+
+                            bool fieldFound = vals.TryGetValue(inFieldId, out fieldVal);
+
+                            if (!fieldFound || fieldVal != PortableBuilderField.RmvMarkerObj)
+                            {
+                                outStream.WriteInt(inFieldId);
+
+                                int fieldLenPos = outStream.Position; // Here we will write length later.
+
+                                outStream.Seek(4, SeekOrigin.Current);
+
+                                if (fieldFound)
+                                {
+                                    // Replace field with new value.
+                                    if (fieldVal != PortableBuilderField.RmvMarkerObj)
+                                        ctx.Writer.Write(fieldVal, null);
+
+                                    vals.Remove(inFieldId);
+                                }
+                                else
+                                {
+                                    // If field was requested earlier, then we must write tracked value
+                                    if (_parent._cache != null && _parent._cache.TryGetValue(inFieldDataPos, out fieldVal))
+                                        ctx.Writer.Write(fieldVal, null);
+                                    else
+                                        // Filed is not tracked, re-write as is.
+                                        Mutate0(ctx, inStream, outStream, false, 0, EmptyVals);                                    
+                                }
+
+                                int fieldEndPos = outStream.Position;
+
+                                outStream.Seek(fieldLenPos, SeekOrigin.Begin);
+                                outStream.WriteInt(fieldEndPos - fieldLenPos - 4);
+                                outStream.Seek(fieldEndPos, SeekOrigin.Begin);
+                            }
+
+                            // Position intput stream pointer after the field.
+                            inStream.Seek(inFieldDataPos + inFieldLen, SeekOrigin.Begin);
+                        }
+
+                        // Write remaining new fields.
+                        foreach (KeyValuePair<int, object> valEntry in vals)
+                        {
+                            if (valEntry.Value != PortableBuilderField.RmvMarkerObj)
+                            {
+                                outStream.WriteInt(valEntry.Key);
+
+                                int fieldLenPos = outStream.Position; // Here we will write length later.
+
+                                outStream.Seek(4, SeekOrigin.Current);
+
+                                ctx.Writer.Write(valEntry.Value, null);
+
+                                int fieldEndPos = outStream.Position;
+
+                                outStream.Seek(fieldLenPos, SeekOrigin.Begin);
+                                outStream.WriteInt(fieldEndPos - fieldLenPos - 4);
+                                outStream.Seek(fieldEndPos, SeekOrigin.Begin);
+                            }
+                        }
+
+                        // Write raw data.
+                        int rawPos = outStream.Position;
+
+                        outStream.Write(inStream.InternalArray, inStartPos + inRawOff, inLen - inRawOff);
+
+                        // Write length and raw data offset.
+                        int outResPos = outStream.Position;
+
+                        outStream.Seek(outStartPos + OffsetLen, SeekOrigin.Begin);
+
+                        outStream.WriteInt(outResPos - outStartPos); // Length.
+                        outStream.WriteInt(rawPos - outStartPos); // Raw offset.
+
+                        outStream.Seek(outResPos, SeekOrigin.Begin);
+                    }
+                }
+                else
+                {
+                    // Object has already been written, write as handle.
+                    outStream.WriteByte(PortableUtils.HdrHnd);
+                    outStream.WriteInt(outStartPos - hndPos);
+                }
+
+                // Synchronize input stream position.
+                inStream.Seek(inStartPos + inLen, SeekOrigin.Begin);
+            }
+            else
+            {
+                // Try writing as well-known type with fixed size.
+                outStream.WriteByte(inHdr);
+
+                if (!WriteAsPredefined(inHdr, inStream, outStream, ctx))
+                    throw new IgniteException("Unexpected header [position=" + (inStream.Position - 1) +
+                        ", header=" + inHdr + ']');
+            }
+        }
+
+        /// <summary>
+        /// Process portable object inverting handles if needed.
+        /// </summary>
+        /// <param name="outStream">Output stream.</param>
+        /// <param name="port">Portable.</param>
+        internal void ProcessPortable(IPortableStream outStream, PortableUserObject port)
+        {
+            // Special case: writing portable object with correct inversions.
+            PortableHeapStream inStream = new PortableHeapStream(port.Data);
+
+            inStream.Seek(port.Offset, SeekOrigin.Begin);
+
+            // Use fresh context to ensure correct portable inversion.
+            Mutate0(new Context(), inStream, outStream, false, 0, EmptyVals);
+        }
+
+        /// <summary>
+        /// Process child builder.
+        /// </summary>
+        /// <param name="outStream">Output stream.</param>
+        /// <param name="builder">Builder.</param>
+        internal void ProcessBuilder(IPortableStream outStream, PortableBuilderImpl builder)
+        {
+            PortableHeapStream inStream = new PortableHeapStream(builder._obj.Data);
+
+            inStream.Seek(builder._obj.Offset, SeekOrigin.Begin);
+
+            // Builder parent context might be null only in one case: if we never met this group of
+            // builders before. In this case we set context to their parent and track it. Context
+            // cleanup will be performed at the very end of build process.
+            if (builder._parent._ctx == null || builder._parent._ctx.Closed)
+                builder._parent._ctx = new Context(_parent._ctx);
+
+            builder.Mutate(inStream, outStream as PortableHeapStream, builder._desc,
+                    builder._hashCode, builder._vals);
+        }
+
+        /// <summary>
+        /// Write object as a predefined type if possible.
+        /// </summary>
+        /// <param name="hdr">Header.</param>
+        /// <param name="inStream">Input stream.</param>
+        /// <param name="outStream">Output stream.</param>
+        /// <param name="ctx">Context.</param>
+        /// <returns><c>True</c> if was written.</returns>
+        private bool WriteAsPredefined(byte hdr, PortableHeapStream inStream, IPortableStream outStream,
+            Context ctx)
+        {
+            switch (hdr)
+            {
+                case PortableUtils.TypeByte:
+                    TransferBytes(inStream, outStream, 1);
+
+                    break;
+
+                case PortableUtils.TypeShort:
+                    TransferBytes(inStream, outStream, 2);
+
+                    break;
+
+                case PortableUtils.TypeInt:
+                    TransferBytes(inStream, outStream, 4);
+
+                    break;
+
+                case PortableUtils.TypeLong:
+                    TransferBytes(inStream, outStream, 8);
+
+                    break;
+
+                case PortableUtils.TypeFloat:
+                    TransferBytes(inStream, outStream, 4);
+
+                    break;
+
+                case PortableUtils.TypeDouble:
+                    TransferBytes(inStream, outStream, 8);
+
+                    break;
+
+                case PortableUtils.TypeChar:
+                    TransferBytes(inStream, outStream, 2);
+
+                    break;
+
+                case PortableUtils.TypeBool:
+                    TransferBytes(inStream, outStream, 1);
+
+                    break;
+
+                case PortableUtils.TypeDecimal:
+                    TransferBytes(inStream, outStream, 4); // Transfer scale
+
+                    int magLen = inStream.ReadInt(); // Transfer magnitude length.
+
+                    outStream.WriteInt(magLen);
+
+                    TransferBytes(inStream, outStream, magLen); // Transfer magnitude.
+
+                    break;
+
+                case PortableUtils.TypeString:
+                    PortableUtils.WriteString(PortableUtils.ReadString(inStream), outStream);
+
+                    break;
+
+                case PortableUtils.TypeGuid:
+                    TransferBytes(inStream, outStream, 16);
+
+                    break;
+
+                case PortableUtils.TypeDate:
+                    TransferBytes(inStream, outStream, 12);
+
+                    break;
+
+                case PortableUtils.TypeArrayByte:
+                    TransferArray(inStream, outStream, 1);
+
+                    break;
+
+                case PortableUtils.TypeArrayShort:
+                    TransferArray(inStream, outStream, 2);
+
+                    break;
+
+                case PortableUtils.TypeArrayInt:
+                    TransferArray(inStream, outStream, 4);
+
+                    break;
+
+                case PortableUtils.TypeArrayLong:
+                    TransferArray(inStream, outStream, 8);
+
+                    break;
+
+                case PortableUtils.TypeArrayFloat:
+                    TransferArray(inStream, outStream, 4);
+
+                    break;
+
+                case PortableUtils.TypeArrayDouble:
+                    TransferArray(inStream, outStream, 8);
+
+                    break;
+
+                case PortableUtils.TypeArrayChar:
+                    TransferArray(inStream, outStream, 2);
+
+                    break;
+
+                case PortableUtils.TypeArrayBool:
+                    TransferArray(inStream, outStream, 1);
+
+                    break;
+
+                case PortableUtils.TypeArrayDecimal:
+                case PortableUtils.TypeArrayString:
+                case PortableUtils.TypeArrayGuid:
+                case PortableUtils.TypeArrayDate:
+                case PortableUtils.TypeArrayEnum:
+                case PortableUtils.TypeArray:
+                    int arrLen = inStream.ReadInt();
+
+                    outStream.WriteInt(arrLen);
+
+                    for (int i = 0; i < arrLen; i++)
+                        Mutate0(ctx, inStream, outStream, false, 0, null);
+
+                    break;
+
+                case PortableUtils.TypeCollection:
+                    int colLen = inStream.ReadInt();
+
+                    outStream.WriteInt(colLen);
+
+                    outStream.WriteByte(inStream.ReadByte());
+
+                    for (int i = 0; i < colLen; i++)
+                        Mutate0(ctx, inStream, outStream, false, 0, EmptyVals);
+
+                    break;
+
+                case PortableUtils.TypeDictionary:
+                    int dictLen = inStream.ReadInt();
+
+                    outStream.WriteInt(dictLen);
+
+                    outStream.WriteByte(inStream.ReadByte());
+
+                    for (int i = 0; i < dictLen; i++)
+                    {
+                        Mutate0(ctx, inStream, outStream, false, 0, EmptyVals);
+                        Mutate0(ctx, inStream, outStream, false, 0, EmptyVals);
+                    }
+
+                    break;
+
+                case PortableUtils.TypeMapEntry:
+                    Mutate0(ctx, inStream, outStream, false, 0, EmptyVals);
+                    Mutate0(ctx, inStream, outStream, false, 0, EmptyVals);
+
+                    break;
+
+                case PortableUtils.TypePortable:
+                    TransferArray(inStream, outStream, 1); // Data array.
+                    TransferBytes(inStream, outStream, 4); // Offset in array.
+
+                    break;
+
+                case PortableUtils.TypeEnum:
+                    TransferBytes(inStream, outStream, 4); // Integer ordinal.
+
+                    break;
+
+                default:
+                    return false;
+            }
+
+            return true;
+        }
+
+        /// <summary>
+        /// Get's metadata field type ID for the given type.
+        /// </summary>
+        /// <param name="type">Type.</param>
+        /// <returns>Type ID.</returns>
+        private static int TypeId(Type type)
+        {
+            int typeId;
+
+            if (TypeIds.TryGetValue(type, out typeId))
+                return typeId;
+            if (type.IsEnum)
+                return PortableUtils.TypeEnum;
+            if (type.IsArray)
+                return type.GetElementType().IsEnum ? PortableUtils.TypeArrayEnum : PortableUtils.TypeArray;
+            PortableCollectionInfo colInfo = PortableCollectionInfo.Info(type);
+
+            return colInfo.IsAny ? colInfo.IsCollection || colInfo.IsGenericCollection ?
+                PortableUtils.TypeCollection : PortableUtils.TypeDictionary : PortableUtils.TypeObject;
+        }
+
+        /// <summary>
+        /// Transfer bytes from one stream to another.
+        /// </summary>
+        /// <param name="inStream">Input stream.</param>
+        /// <param name="outStream">Output stream.</param>
+        /// <param name="cnt">Bytes count.</param>
+        private static void TransferBytes(PortableHeapStream inStream, IPortableStream outStream, int cnt)
+        {
+            outStream.Write(inStream.InternalArray, inStream.Position, cnt);
+
+            inStream.Seek(cnt, SeekOrigin.Current);
+        }
+
+        /// <summary>
+        /// Transfer array of fixed-size elements from one stream to another.
+        /// </summary>
+        /// <param name="inStream">Input stream.</param>
+        /// <param name="outStream">Output stream.</param>
+        /// <param name="elemSize">Element size.</param>
+        private static void TransferArray(PortableHeapStream inStream, IPortableStream outStream,
+            int elemSize)
+        {
+            int len = inStream.ReadInt();
+
+            outStream.WriteInt(len);
+
+            TransferBytes(inStream, outStream, elemSize * len);
+        }
+
+        /// <summary>
+        /// Mutation ocntext.
+        /// </summary>
+        private class Context
+        {
+            /** Map from object position in old portable to position in new portable. */
+            private IDictionary<int, int> _oldToNew;
+
+            /** Parent context. */
+            private readonly Context _parent;
+
+            /** Portable writer. */
+            private readonly PortableWriterImpl _writer;
+
+            /** Children contexts. */
+            private ICollection<Context> _children;
+
+            /** Closed flag; if context is closed, it can no longer be used. */
+            private bool _closed;
+
+            /// <summary>
+            /// Constructor for parent context where writer invocation is not expected.
+            /// </summary>
+            public Context()
+            {
+                // No-op.
+            }
+
+            /// <summary>
+            /// Constructor for parent context.
+            /// </summary>
+            /// <param name="writer">Writer</param>
+            public Context(PortableWriterImpl writer)
+            {
+                _writer = writer;
+            }
+
+            /// <summary>
+            /// Constructor.
+            /// </summary>
+            /// <param name="parent">Parent context.</param>
+            public Context(Context parent)
+            {
+                _parent = parent;
+                
+                _writer = parent._writer;
+
+                if (parent._children == null)
+                    parent._children = new List<Context>();
+
+                parent._children.Add(this);
+            }
+
+            /// <summary>
+            /// Add another old-to-new position mapping.
+            /// </summary>
+            /// <param name="oldPos">Old position.</param>
+            /// <param name="newPos">New position.</param>
+            /// <param name="hndPos">Handle position.</param>
+            /// <returns><c>True</c> if ampping was added, <c>false</c> if mapping already existed and handle
+            /// position in the new object is returned.</returns>
+            public bool AddOldToNew(int oldPos, int newPos, out int hndPos)
+            {
+                if (_oldToNew == null)
+                    _oldToNew = new Dictionary<int, int>();
+
+                if (_oldToNew.TryGetValue(oldPos, out hndPos))
+                    return false;
+                _oldToNew[oldPos] = newPos;
+
+                return true;
+            }
+
+            /// <summary>
+            /// Get mapping of old position to the new one.
+            /// </summary>
+            /// <param name="oldPos">Old position.</param>
+            /// <param name="newPos">New position.</param>
+            /// <returns><c>True</c> if mapping exists.</returns>
+            public bool OldToNew(int oldPos, out int newPos)
+            {
+                return _oldToNew.TryGetValue(oldPos, out newPos);
+            }
+
+            /// <summary>
+            /// Writer.
+            /// </summary>
+            public PortableWriterImpl Writer
+            {
+                get { return _writer; }
+            }
+
+            /// <summary>
+            /// Closed flag.
+            /// </summary>
+            public bool Closed
+            {
+                get
+                {
+                    return _closed;
+                }
+                set
+                {
+                    Context ctx = this;
+
+                    while (ctx != null)
+                    {
+                        ctx._closed = value;
+
+                        if (_children != null) {
+                            foreach (Context child in _children)
+                                child.Closed = value;
+                        }
+
+                        ctx = ctx._parent;
+                    }
+                }
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/f2eb16cd/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableCollectionInfo.cs
----------------------------------------------------------------------
diff --git a/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableCollectionInfo.cs b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableCollectionInfo.cs
new file mode 100644
index 0000000..fc61833
--- /dev/null
+++ b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableCollectionInfo.cs
@@ -0,0 +1,251 @@
+/*
+ * 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.Impl.Portable
+{
+    using System;
+    using System.Collections.Concurrent;
+    using System.Collections.Generic;
+    using System.Diagnostics;
+    using System.Reflection;
+    using Apache.Ignite.Core.Impl.Common;
+
+    /**
+     * <summary>Collection info helper.</summary>
+     */
+    internal class PortableCollectionInfo
+    {
+        /** Flag: none. */
+        private const byte FlagNone = 0;
+
+        /** Flag: generic dictionary. */
+        private const byte FlagGenericDictionary = 1;
+
+        /** Flag: generic collection. */
+        private const byte FlagGenericCollection = 2;
+
+        /** Flag: dictionary. */
+        private const byte FlagDictionary = 3;
+
+        /** Flag: collection. */
+        private const byte FlagCollection = 4;
+
+        /** Cache "none" value. */
+        private static readonly PortableCollectionInfo None =
+            new PortableCollectionInfo(FlagNone, null, null, null);
+
+        /** Cache "dictionary" value. */
+        private static readonly PortableCollectionInfo Dictionary =
+            new PortableCollectionInfo(FlagDictionary, PortableSystemHandlers.WriteHndDictionary, null, null);
+
+        /** Cache "collection" value. */
+        private static readonly PortableCollectionInfo Collection =
+            new PortableCollectionInfo(FlagCollection, PortableSystemHandlers.WriteHndCollection, null, null);
+
+        /** Cached infos. */
+        private static readonly IDictionary<Type, PortableCollectionInfo> Infos =
+            new ConcurrentDictionary<Type, PortableCollectionInfo>(64, 32);
+
+        /**
+         * <summary>Get collection info for type.</summary>
+         * <param name="type">Type.</param>
+         * <returns>Collection info.</returns>
+         */
+        public static PortableCollectionInfo Info(Type type)
+        {
+            PortableCollectionInfo info;
+
+            if (!Infos.TryGetValue(type, out info))
+            {
+                info = Info0(type);
+
+                Infos[type] = info;
+            }
+
+            return info;
+        }
+
+        /**
+         * <summary>Internal routine to get collection info for type.</summary>
+         * <param name="type">Type.</param>
+         * <returns>Collection info.</returns>
+         */
+        private static PortableCollectionInfo Info0(Type type)
+        {
+            if (type.IsGenericType)
+            {
+                if (type.GetGenericTypeDefinition() == PortableUtils.TypGenericDictionary)
+                {
+                    MethodInfo writeMthd =
+                        PortableUtils.MtdhWriteGenericDictionary.MakeGenericMethod(type.GetGenericArguments());
+                    MethodInfo readMthd =
+                        PortableUtils.MtdhReadGenericDictionary.MakeGenericMethod(type.GetGenericArguments());
+
+                    return new PortableCollectionInfo(FlagGenericDictionary,
+                        PortableSystemHandlers.WriteHndGenericDictionary, writeMthd, readMthd);
+                }
+
+                Type genTyp = type.GetInterface(PortableUtils.TypGenericDictionary.FullName);
+
+                if (genTyp != null)
+                {
+                    MethodInfo writeMthd =
+                        PortableUtils.MtdhWriteGenericDictionary.MakeGenericMethod(genTyp.GetGenericArguments());
+                    MethodInfo readMthd =
+                        PortableUtils.MtdhReadGenericDictionary.MakeGenericMethod(genTyp.GetGenericArguments());
+
+                    return new PortableCollectionInfo(FlagGenericDictionary,
+                        PortableSystemHandlers.WriteHndGenericDictionary, writeMthd, readMthd);
+                }
+
+                if (type.GetGenericTypeDefinition() == PortableUtils.TypGenericCollection)
+                {
+                    MethodInfo writeMthd =
+                        PortableUtils.MtdhWriteGenericCollection.MakeGenericMethod(type.GetGenericArguments());
+                    MethodInfo readMthd =
+                        PortableUtils.MtdhReadGenericCollection.MakeGenericMethod(type.GetGenericArguments());
+
+                    return new PortableCollectionInfo(FlagGenericCollection,
+                        PortableSystemHandlers.WriteHndGenericCollection, writeMthd, readMthd);
+                }
+
+                genTyp = type.GetInterface(PortableUtils.TypGenericCollection.FullName);
+
+                if (genTyp != null)
+                {
+                    MethodInfo writeMthd =
+                        PortableUtils.MtdhWriteGenericCollection.MakeGenericMethod(genTyp.GetGenericArguments());
+                    MethodInfo readMthd =
+                        PortableUtils.MtdhReadGenericCollection.MakeGenericMethod(genTyp.GetGenericArguments());
+
+                    return new PortableCollectionInfo(FlagGenericCollection,
+                        PortableSystemHandlers.WriteHndGenericCollection, writeMthd, readMthd);
+                }
+            }
+
+            if (type == PortableUtils.TypDictionary || type.GetInterface(PortableUtils.TypDictionary.FullName) != null)
+                return Dictionary;
+            if (type == PortableUtils.TypCollection || type.GetInterface(PortableUtils.TypCollection.FullName) != null)
+                return Collection;
+            return None;
+        }
+
+        /** Flag. */
+        private readonly byte _flag;
+
+        /** Write handler. */
+        private readonly PortableSystemWriteDelegate _writeHnd;
+
+        /** Generic write func. */
+        private readonly Action<object, PortableWriterImpl> _writeFunc;
+
+        /** Generic read func. */
+        private readonly Func<PortableReaderImpl, object, object> _readFunc;
+
+        /**
+         * <summary>Constructor.</summary>
+         * <param name="flag0">Flag.</param>
+         * <param name="writeHnd0">Write handler.</param>
+         * <param name="writeMthd0">Generic write method.</param>
+         * <param name="readMthd0">Generic read method.</param>
+         */
+        private PortableCollectionInfo(byte flag0, PortableSystemWriteDelegate writeHnd0,
+            MethodInfo writeMthd0, MethodInfo readMthd0)
+        {
+            _flag = flag0;
+            _writeHnd = writeHnd0;
+
+            if (writeMthd0 != null)
+                _writeFunc = DelegateConverter.CompileFunc<Action<object, PortableWriterImpl>>(null, writeMthd0, null,
+                    new[] {true, false, false});
+
+            if (readMthd0 != null)
+                _readFunc = DelegateConverter.CompileFunc<Func<PortableReaderImpl, object, object>>(null, readMthd0, 
+                    null, new[] {false, true, false});
+        }
+
+        /**
+         * <summary>Generic dictionary flag.</summary>
+         */
+        public bool IsGenericDictionary
+        {
+            get { return _flag == FlagGenericDictionary; }
+        }
+
+        /**
+         * <summary>Generic collection flag.</summary>
+         */
+        public bool IsGenericCollection
+        {
+            get { return _flag == FlagGenericCollection; }
+        }
+
+        /**
+         * <summary>Dictionary flag.</summary>
+         */
+        public bool IsDictionary
+        {
+            get { return _flag == FlagDictionary; }
+        }
+
+        /**
+         * <summary>Collection flag.</summary>
+         */
+        public bool IsCollection
+        {
+            get { return _flag == FlagCollection; }
+        }
+
+        /**
+         * <summary>Whether at least one flag is set..</summary>
+         */
+        public bool IsAny
+        {
+            get { return _flag != FlagNone; }
+        }
+
+        /**
+         * <summary>Write handler.</summary>
+         */
+        public PortableSystemWriteDelegate WriteHandler
+        {
+            get { return _writeHnd; }
+        }
+
+        /// <summary>
+        /// Reads the generic collection.
+        /// </summary>
+        public object ReadGeneric(PortableReaderImpl reader)
+        {
+            Debug.Assert(reader != null);
+            Debug.Assert(_readFunc != null);
+
+            return _readFunc(reader, null);
+        }
+
+        /// <summary>
+        /// Writes the generic collection.
+        /// </summary>
+        public void WriteGeneric(PortableWriterImpl writer, object value)
+        {
+            Debug.Assert(writer != null);
+            Debug.Assert(_writeFunc != null);
+
+            _writeFunc(value, writer);
+        }
+    }
+}