This is an automated email from the ASF dual-hosted git repository.

wesm pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow.git


The following commit(s) were added to refs/heads/master by this push:
     new 044b418  ARROW-4284: [C#] File / Stream serialization fails due to 
type mismatch / missing footer
044b418 is described below

commit 044b418fa108a57f0b4e2e887546cc3e68271397
Author: Christopher Hutchinson <[email protected]>
AuthorDate: Tue Jan 22 18:56:39 2019 -0600

    ARROW-4284: [C#] File / Stream serialization fails due to type mismatch / 
missing footer
    
    - refactored ArrowBuffer API to reflect spec (immutable, value-semantics)
    - refactored memory allocation API (moved padding responsibility to buffer, 
removed DefaultMemoryPool)
    - fixed bug where reallocated memory didn't have padding zeroed
    - fixed serialization bug due to faulty buffer growth function
    - fixed brittle array data type visitor pattern implementation
    - added unit tests for buffers and buffer builder API
    
    Author: Christopher Hutchinson <[email protected]>
    
    Closes #3462 from chutchinson/bug/4284-stream-serialization-failure and 
squashes the following commits:
    
    fb2cc623a <Christopher Hutchinson>  File / Stream serialization fails due 
to type mismatch / missing footer
---
 csharp/build/Common.props                          |   3 -
 csharp/src/Apache.Arrow/Arrays/Array.cs            |  17 +-
 csharp/src/Apache.Arrow/Arrays/ArrayData.cs        |   5 +-
 csharp/src/Apache.Arrow/Arrays/BinaryArray.cs      |  17 +-
 csharp/src/Apache.Arrow/Arrays/BooleanArray.cs     |   3 +-
 csharp/src/Apache.Arrow/Arrays/ListArray.cs        |  10 +-
 csharp/src/Apache.Arrow/Arrays/PrimitiveArray.cs   |   9 +-
 csharp/src/Apache.Arrow/Arrays/StringArray.cs      |   6 +-
 csharp/src/Apache.Arrow/Arrays/TimestampArray.cs   |   6 +-
 csharp/src/Apache.Arrow/Arrays/UnionArray.cs       |   4 +-
 csharp/src/Apache.Arrow/ArrowBuffer.Builder.cs     | 135 ++++++++++++----
 csharp/src/Apache.Arrow/ArrowBuffer.cs             | 107 ++-----------
 csharp/src/Apache.Arrow/BitUtility.cs              |   6 +-
 csharp/src/Apache.Arrow/Bitmap.cs                  |  75 ---------
 .../DateType.cs => Extensions/SpanExtensions.cs}   |  19 ++-
 csharp/src/Apache.Arrow/Ipc/ArrowFileReader.cs     |   7 +-
 csharp/src/Apache.Arrow/Ipc/ArrowFileWriter.cs     |  22 +--
 csharp/src/Apache.Arrow/Ipc/ArrowStreamReader.cs   |   7 +-
 csharp/src/Apache.Arrow/Ipc/ArrowStreamWriter.cs   |  41 +++--
 .../src/Apache.Arrow/Memory/DefaultMemoryPool.cs   |  38 -----
 csharp/src/Apache.Arrow/Memory/MemoryPool.cs       |  43 +++--
 csharp/src/Apache.Arrow/Memory/NativeMemory.cs     |   8 +-
 csharp/src/Apache.Arrow/Memory/NativeMemoryPool.cs |  28 +---
 csharp/src/Apache.Arrow/Types/ArrowType.cs         |  15 ++
 csharp/src/Apache.Arrow/Types/BinaryType.cs        |   9 +-
 csharp/src/Apache.Arrow/Types/BooleanType.cs       |  11 +-
 csharp/src/Apache.Arrow/Types/Date32Type.cs        |  11 +-
 csharp/src/Apache.Arrow/Types/Date64Type.cs        |  11 +-
 csharp/src/Apache.Arrow/Types/DateType.cs          |   3 -
 csharp/src/Apache.Arrow/Types/DecimalType.cs       |   2 +-
 csharp/src/Apache.Arrow/Types/DoubleType.cs        |  11 +-
 .../src/Apache.Arrow/Types/FixedSizeBinaryType.cs  |  11 +-
 csharp/src/Apache.Arrow/Types/FixedWidthType.cs    |   3 -
 csharp/src/Apache.Arrow/Types/FloatType.cs         |  11 +-
 csharp/src/Apache.Arrow/Types/FloatingPointType.cs |   3 -
 csharp/src/Apache.Arrow/Types/HalfFloatType.cs     |  11 +-
 csharp/src/Apache.Arrow/Types/IArrowType.cs        |   3 -
 csharp/src/Apache.Arrow/Types/IArrowTypeVisitor.cs |   3 -
 csharp/src/Apache.Arrow/Types/Int16Type.cs         |   8 +-
 csharp/src/Apache.Arrow/Types/Int32Type.cs         |   8 +-
 csharp/src/Apache.Arrow/Types/Int64Type.cs         |   8 +-
 csharp/src/Apache.Arrow/Types/Int8Type.cs          |  11 +-
 csharp/src/Apache.Arrow/Types/IntervalUnit.cs      |  11 +-
 csharp/src/Apache.Arrow/Types/ListType.cs          |  10 +-
 csharp/src/Apache.Arrow/Types/NullType.cs          |  11 +-
 csharp/src/Apache.Arrow/Types/NumberType.cs        |   3 -
 csharp/src/Apache.Arrow/Types/StringType.cs        |  11 +-
 csharp/src/Apache.Arrow/Types/StructType.cs        |   8 +-
 csharp/src/Apache.Arrow/Types/Time32Type.cs        |  11 +-
 csharp/src/Apache.Arrow/Types/Time64Type.cs        |  11 +-
 csharp/src/Apache.Arrow/Types/TimeType.cs          |   3 -
 csharp/src/Apache.Arrow/Types/TimestampType.cs     |  11 +-
 csharp/src/Apache.Arrow/Types/UInt16Type.cs        |   8 +-
 csharp/src/Apache.Arrow/Types/UInt32Type.cs        |   8 +-
 csharp/src/Apache.Arrow/Types/UInt64Type.cs        |   8 +-
 csharp/src/Apache.Arrow/Types/UInt8Type.cs         |   8 +-
 csharp/src/Apache.Arrow/Types/UnionType.cs         |   8 +-
 .../Apache.Arrow.Tests/Apache.Arrow.Tests.csproj   |   1 +
 .../Apache.Arrow.Tests/ArrowBufferBuilderTests.cs  | 176 +++++++++++++++++++++
 csharp/test/Apache.Arrow.Tests/ArrowBufferTests.cs |  35 ++--
 .../Fixtures/DefaultMemoryPoolFixture.cs           |   3 +-
 61 files changed, 516 insertions(+), 598 deletions(-)

diff --git a/csharp/build/Common.props b/csharp/build/Common.props
index 9e7901d..cebd07c 100644
--- a/csharp/build/Common.props
+++ b/csharp/build/Common.props
@@ -2,7 +2,4 @@
     <PropertyGroup>
         <BaseOutputPath>../../artifacts/$(AssemblyName)</BaseOutputPath>
     </PropertyGroup>
-    <Target Name="Clean">  
-        <RemoveDir Directories="../../artifacts" />  
-    </Target>
 </Project>
\ No newline at end of file
diff --git a/csharp/src/Apache.Arrow/Arrays/Array.cs 
b/csharp/src/Apache.Arrow/Arrays/Array.cs
index a9609f2..e795ad9 100644
--- a/csharp/src/Apache.Arrow/Arrays/Array.cs
+++ b/csharp/src/Apache.Arrow/Arrays/Array.cs
@@ -33,8 +33,6 @@ namespace Apache.Arrow
 
         public int NullCount => Data.NullCount;
 
-        public Bitmap NullBitmap => Data.NullBitmap;
-
         public ArrowBuffer NullBitmapBuffer => Data.Buffers[0];
 
         public virtual void Accept(IArrowArrayVisitor visitor)
@@ -43,7 +41,7 @@ namespace Apache.Arrow
         }
 
         public bool IsValid(int index) =>
-            NullBitmapBuffer == null || NullBitmap.IsSet(index);
+            NullBitmapBuffer.IsEmpty || 
BitUtility.GetBit(NullBitmapBuffer.Span, index);
 
         public bool IsNull(int index) => !IsValid(index);
 
@@ -51,13 +49,14 @@ namespace Apache.Arrow
         internal static void Accept<T>(T array, IArrowArrayVisitor visitor)
             where T : class, IArrowArray
         {
-            if (visitor is IArrowArrayVisitor<T> v)
-            {
-                v.Visit(array);
-            }
-            else
+            switch (visitor)
             {
-                visitor.Visit(array);
+                case IArrowArrayVisitor<T> typedVisitor:
+                    typedVisitor.Visit(array);
+                    break;
+                default:
+                    visitor.Visit(array);
+                    break;
             }
         }
     }
diff --git a/csharp/src/Apache.Arrow/Arrays/ArrayData.cs 
b/csharp/src/Apache.Arrow/Arrays/ArrayData.cs
index a8d745c..2074f12 100644
--- a/csharp/src/Apache.Arrow/Arrays/ArrayData.cs
+++ b/csharp/src/Apache.Arrow/Arrays/ArrayData.cs
@@ -19,7 +19,7 @@ using System.Linq;
 
 namespace Apache.Arrow
 {
-    public class ArrayData
+    public sealed class ArrayData
     {
         public readonly IArrowType DataType;
         public readonly int Length;
@@ -28,9 +28,6 @@ namespace Apache.Arrow
         public readonly ArrowBuffer[] Buffers;
         public readonly ArrayData[] Children;
 
-        public ArrowBuffer NullBitmapBuffer => Buffers[0];
-        public Bitmap NullBitmap => NullBitmapBuffer;
-
         public ArrayData(
             IArrowType dataType,
             int length, int nullCount = 0, int offset = 0,
diff --git a/csharp/src/Apache.Arrow/Arrays/BinaryArray.cs 
b/csharp/src/Apache.Arrow/Arrays/BinaryArray.cs
index cbe64df..12ef5ee 100644
--- a/csharp/src/Apache.Arrow/Arrays/BinaryArray.cs
+++ b/csharp/src/Apache.Arrow/Arrays/BinaryArray.cs
@@ -50,28 +50,31 @@ namespace Apache.Arrow
 
         public ArrowBuffer ValueBuffer => Data.Buffers[2];
 
+        public ReadOnlySpan<int> ValueOffsets => 
ValueOffsetsBuffer.Span.CastTo<int>().Slice(0, Length + 1);
+
+        public ReadOnlySpan<byte> Values => ValueBuffer.Span.CastTo<byte>();
+
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public int GetValueOffset(int index)
         {
-            var offsets = ValueOffsetsBuffer.GetSpan<int>();
-            return offsets[Offset + index];
+            return ValueOffsets[Offset + index];
         }
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public int GetValueLength(int index)
         {
-            var offsets = ValueOffsetsBuffer.GetSpan<int>();
+            var offsets = ValueOffsets;
             var offset = Offset + index;
+
             return offsets[offset + 1] - offsets[offset];
         }
 
-        public ReadOnlySpan<byte> GetValue(int index)
+        public ReadOnlySpan<byte> GetBytes(int index)
         {
             var offset = GetValueOffset(index);
             var length = GetValueLength(index);
-            var values = ValueBuffer.GetSpan<byte>();
-
-            return values.Slice(offset, length);
+            
+            return ValueBuffer.Span.Slice(offset, length);
         }
 
     }
diff --git a/csharp/src/Apache.Arrow/Arrays/BooleanArray.cs 
b/csharp/src/Apache.Arrow/Arrays/BooleanArray.cs
index f419712..ddee188 100644
--- a/csharp/src/Apache.Arrow/Arrays/BooleanArray.cs
+++ b/csharp/src/Apache.Arrow/Arrays/BooleanArray.cs
@@ -39,8 +39,7 @@ namespace Apache.Arrow
             if (IsNull(index))
                 return null;
 
-            var span = GetSpan();
-            return BitUtility.GetBit(span, index);
+            return BitUtility.GetBit(Values, index);
         }
     }
 }
diff --git a/csharp/src/Apache.Arrow/Arrays/ListArray.cs 
b/csharp/src/Apache.Arrow/Arrays/ListArray.cs
index e3872bc..3540f5a 100644
--- a/csharp/src/Apache.Arrow/Arrays/ListArray.cs
+++ b/csharp/src/Apache.Arrow/Arrays/ListArray.cs
@@ -13,6 +13,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+using System;
 using Apache.Arrow.Types;
 
 namespace Apache.Arrow
@@ -23,6 +24,8 @@ namespace Apache.Arrow
 
         public ArrowBuffer ValueOffsetsBuffer => Data.Buffers[1];
 
+        public ReadOnlySpan<int> ValueOffsets => 
ValueOffsetsBuffer.Span.CastTo<int>().Slice(0, Length + 1);
+
         public ListArray(IArrowType dataType, int length,
             ArrowBuffer valueOffsetsBuffer, IArrowArray values,
             ArrowBuffer nullBitmapBuffer, int nullCount = 0, int offset = 0)
@@ -43,14 +46,13 @@ namespace Apache.Arrow
 
         public int GetValueOffset(int index)
         {
-            var span = ValueOffsetsBuffer.GetSpan<int>(Offset);
-            return span[index];
+            return ValueOffsets[index];
         }
 
         public int GetValueLength(int index)
         {
-            var span = ValueOffsetsBuffer.GetSpan<int>(Offset);
-            return span[index + 1] - span[index];
+            var offsets = ValueOffsets;
+            return offsets[index + 1] - offsets[index];
         }
     }
 }
diff --git a/csharp/src/Apache.Arrow/Arrays/PrimitiveArray.cs 
b/csharp/src/Apache.Arrow/Arrays/PrimitiveArray.cs
index 6dcb103..617bddc 100644
--- a/csharp/src/Apache.Arrow/Arrays/PrimitiveArray.cs
+++ b/csharp/src/Apache.Arrow/Arrays/PrimitiveArray.cs
@@ -16,8 +16,6 @@
 using System;
 using System.Collections.Generic;
 using System.Runtime.CompilerServices;
-using Apache.Arrow.Memory;
-using Apache.Arrow.Types;
 
 namespace Apache.Arrow
 {
@@ -33,18 +31,17 @@ namespace Apache.Arrow
 
     public ArrowBuffer ValueBuffer => Data.Buffers[1];
 
-    public Span<T> GetSpan() => ValueBuffer.GetSpan<T>().Slice(0, Length);
+    public ReadOnlySpan<T> Values => ValueBuffer.Span.CastTo<T>().Slice(0, 
Length);
 
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     public T? GetValue(int index)
     {
-        var span = GetSpan();
-        return IsValid(index) ? span[index] : (T?) null;
+        return IsValid(index) ? Values[index] : (T?) null;
     }
 
     public IList<T?> ToList(bool includeNulls = false)
     {
-        var span = GetSpan();
+        var span = Values;
         var list = new List<T?>(span.Length);
 
         for (var i = 0; i < span.Length; i++)
diff --git a/csharp/src/Apache.Arrow/Arrays/StringArray.cs 
b/csharp/src/Apache.Arrow/Arrays/StringArray.cs
index 3c8f8c0..9ea9522 100644
--- a/csharp/src/Apache.Arrow/Arrays/StringArray.cs
+++ b/csharp/src/Apache.Arrow/Arrays/StringArray.cs
@@ -39,12 +39,12 @@ namespace Apache.Arrow
         {
             encoding = encoding ?? Encoding.UTF8;
 
-            var value = GetValue(index);
+            var bytes = GetBytes(index);
 
             unsafe
             {
-                fixed (byte* data = &MemoryMarshal.GetReference(value))
-                    return encoding.GetString(data, value.Length);
+                fixed (byte* data = &MemoryMarshal.GetReference(bytes))
+                    return encoding.GetString(data, bytes.Length);
             }
         }
     }
diff --git a/csharp/src/Apache.Arrow/Arrays/TimestampArray.cs 
b/csharp/src/Apache.Arrow/Arrays/TimestampArray.cs
index 174f650..f9fd0ae 100644
--- a/csharp/src/Apache.Arrow/Arrays/TimestampArray.cs
+++ b/csharp/src/Apache.Arrow/Arrays/TimestampArray.cs
@@ -38,14 +38,12 @@ namespace Apache.Arrow
 
         public DateTimeOffset? GetTimestamp(int index)
         {
-            var span = GetSpan();
-
             if (IsNull(index))
             {
                 return null;
             }
 
-            var value = span[index];
+            var value = Values[index];
             var type = Data.DataType as TimestampType;
 
             switch (type.Unit)
@@ -60,7 +58,7 @@ namespace Apache.Arrow
                     return DateTimeOffset.FromUnixTimeSeconds(value);
                 default:
                     throw new InvalidDataException(
-                        string.Format("Unsupported timestamp unit <{0}>", 
type.Unit));
+                        $"Unsupported timestamp unit <{type.Unit}>");
             }
         }
     }
diff --git a/csharp/src/Apache.Arrow/Arrays/UnionArray.cs 
b/csharp/src/Apache.Arrow/Arrays/UnionArray.cs
index 7ba7f9f..8bccea2 100644
--- a/csharp/src/Apache.Arrow/Arrays/UnionArray.cs
+++ b/csharp/src/Apache.Arrow/Arrays/UnionArray.cs
@@ -28,9 +28,9 @@ namespace Apache.Arrow
 
         public ArrowBuffer ValueOffsetBuffer => Data.Buffers[2];
 
-        public ReadOnlySpan<byte> TypeIds => TypeBuffer.GetSpan<byte>();
+        public ReadOnlySpan<byte> TypeIds => TypeBuffer.Span;
 
-        public ReadOnlySpan<int> ValueOffsets => 
ValueOffsetBuffer.GetSpan<int>();
+        public ReadOnlySpan<int> ValueOffsets => 
ValueOffsetBuffer.Span.CastTo<int>().Slice(0, Length + 1);
 
         public UnionArray(ArrayData data) 
             : base(data)
diff --git a/csharp/src/Apache.Arrow/ArrowBuffer.Builder.cs 
b/csharp/src/Apache.Arrow/ArrowBuffer.Builder.cs
index a85fa2d..7ab26fa 100644
--- a/csharp/src/Apache.Arrow/ArrowBuffer.Builder.cs
+++ b/csharp/src/Apache.Arrow/ArrowBuffer.Builder.cs
@@ -17,70 +17,147 @@ using Apache.Arrow.Memory;
 using System;
 using System.Collections.Generic;
 using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
 
 namespace Apache.Arrow
 {
-    public partial class ArrowBuffer
+    public partial struct ArrowBuffer
     {
-        /// <summary>
-        /// Builds an Arrow buffer from primitive values.
-        /// </summary>
-        /// <typeparam name="T">Primitive type</typeparam>
         public class Builder<T>
             where T : struct
         {
             private readonly int _size;
-            private readonly MemoryPool _pool;
-            private Memory<byte> _memory;
-            private int _offset;
+            private byte[] _buffer;
 
-            public Builder(int initialCapacity = 8, MemoryPool pool = default)
-            {
-                if (initialCapacity <= 0) initialCapacity = 1;
-                if (pool == null) pool = DefaultMemoryPool.Instance.Value;
+            public int Capacity => _buffer.Length / _size;
+            public int Length { get; private set; }
 
+            public Builder(int capacity = 8)
+            {
                 _size = Unsafe.SizeOf<T>();
-                _pool = pool;
-                _memory = _pool.Allocate(initialCapacity * _size);
+                _buffer = new byte[capacity * _size];
+
+                Length = 0;
+            }
+
+            public Builder<T> Append(ArrowBuffer buffer)
+            {
+                Append(buffer.Span.CastTo<T>());
+                return this;
             }
 
             public Builder<T> Append(T value)
             {
-                var span = GetSpan();
+                var span = EnsureCapacity(1);
+                span[Length++] = value;
+                return this;
+            }
+
+            public Builder<T> Append(ReadOnlySpan<T> source)
+            {
+                var span = EnsureCapacity(source.Length);
+                source.CopyTo(span.Slice(Length, source.Length));
+                Length += source.Length;
+                return this;
+            }
 
-                if (_offset + 1 >= span.Length)
+            public Builder<T> Append(Func<IEnumerable<T>> fn)
+            {
+                if (fn != null)
                 {
-                    // TODO: Consider a specifiable growth strategy
+                    AppendRange(fn());
+                }
 
-                    _memory = _pool.Reallocate(_memory, (_memory.Length * 3) / 
2);
+                return this;
+            }
+
+            public Builder<T> AppendRange(IEnumerable<T> values)
+            {
+                if (values != null)
+                {
+                    foreach (var v in values)
+                    {
+                        Append(v);
+                    }
                 }
 
-                span[_offset++] = value;
                 return this;
             }
 
-            public Builder<T> Set(int index, T value)
+            public Builder<T> Reserve(int capacity)
             {
-                var span = GetSpan();
-                span[index] = value;
+                EnsureCapacity(capacity);
+                return this;
+            }
+
+            public Builder<T> Resize(int capacity)
+            {
+                if (capacity < 0)
+                {
+                    throw new ArgumentOutOfRangeException(nameof(capacity));
+                }
+
+                Reallocate(capacity);
+                Length = Math.Min(Length, capacity);
+
                 return this;
             }
 
             public Builder<T> Clear()
             {
-                var span = GetSpan();
-                span.Fill(default);
+                Span.Fill(default);
+                Length = 0;
                 return this;
             }
 
-            public ArrowBuffer Build()
+            public ArrowBuffer Build(MemoryPool pool = default)
+            {
+                var length = BitUtility.RoundUpToMultipleOf64(_buffer.Length);
+                var memoryPool = pool ?? MemoryPool.Default.Value;
+                var memory = memoryPool.Allocate(length);
+
+                Memory.CopyTo(memory);
+
+                return new ArrowBuffer(memory);
+            }
+
+            private Span<T> EnsureCapacity(int len)
             {
-                return new ArrowBuffer(_memory, _offset);
+                var targetCapacity = Length + len;
+
+                if (targetCapacity > Capacity)
+                {
+                    // TODO: specifiable growth strategy
+
+                    var capacity = Math.Max(
+                        targetCapacity * _size, _buffer.Length * 2);
+
+                    Reallocate(capacity);
+                }
+
+                return Span;
             }
 
-            [MethodImpl(MethodImplOptions.AggressiveInlining)]
-            private Span<T> GetSpan() => MemoryMarshal.Cast<byte, 
T>(_memory.Span);
+            private void Reallocate(int length)
+            {
+                if (length < 0)
+                {
+                    throw new ArgumentOutOfRangeException(nameof(length));
+                }
+
+                if (length != 0)
+                {
+                    System.Array.Resize(ref _buffer, length);
+                }
+            }
+
+            private Memory<byte> Memory => _buffer;
+
+            private Span<T> Span
+            {
+                [MethodImpl(MethodImplOptions.AggressiveInlining)]
+                get => Memory.Span.CastTo<T>();
+            }
         }
+
     }
 }
diff --git a/csharp/src/Apache.Arrow/ArrowBuffer.cs 
b/csharp/src/Apache.Arrow/ArrowBuffer.cs
index ec2c3cb..8901ff9 100644
--- a/csharp/src/Apache.Arrow/ArrowBuffer.cs
+++ b/csharp/src/Apache.Arrow/ArrowBuffer.cs
@@ -13,116 +13,43 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-using Apache.Arrow.Memory;
 using System;
-using System.Buffers;
-using System.IO;
-using System.Runtime.InteropServices;
-using System.Threading;
-using System.Threading.Tasks;
+using System.Runtime.CompilerServices;
+using Apache.Arrow.Memory;
 
 namespace Apache.Arrow
 {
-    public partial class ArrowBuffer: IEquatable<ArrowBuffer>
+    public readonly partial struct ArrowBuffer: IEquatable<ArrowBuffer>
     {
-        public ArrowBuffer(Memory<byte> data, int size)
+        public static ArrowBuffer Empty => new ArrowBuffer(Memory<byte>.Empty);
+
+        private ArrowBuffer(Memory<byte> data)
         {
             Memory = data;
-            Size = size;
         }
 
-        /// <summary>
-        /// Allocates an Arrow buffer from a memory pool.
-        /// </summary>
-        /// <param name="size">Size of buffer (in bytes) to allocate.</param>
-        /// <param name="memoryPool">Memory pool to use for allocation. If 
null, a default memory pool is used.</param>
-        /// <returns></returns>
-        public static ArrowBuffer Allocate(int size, MemoryPool memoryPool = 
null)
-        {
-            if (memoryPool == null)
-                memoryPool = DefaultMemoryPool.Instance.Value;
+        public ReadOnlyMemory<byte> Memory { get; }
 
-            var buffer = memoryPool.Allocate(size);
+        public bool IsEmpty => Memory.IsEmpty;
 
-            return new ArrowBuffer(buffer, size);
-        }
+        public int Length => Memory.Length;
 
-        /// <summary>
-        /// Allocates an Arrow buffer the same length as the incoming data, 
then
-        /// copies the specified data to the arrow buffer.
-        /// </summary>
-        /// <param name="data">Data to copy into a new arrow buffer.</param>
-        /// <param name="memoryPool">Memory pool to use for allocation. If 
null, a default memory pool is used.</param>
-        /// <returns></returns>
-        public static ArrowBuffer FromMemory(Memory<byte> data, MemoryPool 
memoryPool = default)
+        public ReadOnlySpan<byte> Span
         {
-            var buffer = Allocate(data.Length, memoryPool);
-            data.CopyTo(buffer.Memory);
-            return buffer;
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            get => Memory.Span;
         }
 
-        public async Task CopyToAsync(Stream stream, CancellationToken 
cancellationToken = default)
+        public ArrowBuffer Clone(MemoryPool pool = default)
         {
-            const float chunkSize = 8192f;
-
-            // TODO: Is there a better copy mechanism to use here that does 
not involve allocating buffers and targets .NET Standard 1.3?
-            // NOTE: Consider specialization for .NET Core 2.1
-
-            var length = Convert.ToInt32(chunkSize);
-            var buffer = ArrayPool<byte>.Shared.Rent(length);
-            var count = Convert.ToInt32(Math.Ceiling(Memory.Length / 
chunkSize));
-            var offset = 0;
-
-            try
-            {
-                for (var i = 0; i < count; i++)
-                {
-                    var n = Math.Min(length, Memory.Length);
-                    var slice = Memory.Slice(offset, n);
-
-                    slice.CopyTo(buffer);
-
-                    await stream.WriteAsync(buffer, 0, n, cancellationToken);
-
-                    offset += n;
-                }
-            }
-            finally
-            {
-                if (buffer != null)
-                {
-                    ArrayPool<byte>.Shared.Return(buffer);
-                }
-            }
+            return new Builder<byte>(Span.Length)
+                .Append(Span)
+                .Build(pool);
         }
 
-        public Memory<byte> Memory { get; }
-
-        public bool IsEmpty => Memory.IsEmpty;
-
-        public int Size { get; }
-
-        public int Capacity => Memory.Length;
-
-        public Span<T> GetSpan<T>(int offset)
-            where T : struct =>
-            MemoryMarshal.Cast<byte, T>(
-                Memory.Span.Slice(offset));
-
-        public Span<T> GetSpan<T>(int offset, int length)
-            where T : struct =>
-            MemoryMarshal.Cast<byte, T>(
-                Memory.Span.Slice(offset, length));
-
-        public Span<T> GetSpan<T>()
-            where T: struct =>
-            MemoryMarshal.Cast<byte, T>(Memory.Span);
-
         public bool Equals(ArrowBuffer other)
         {
-            var lhs = GetSpan<byte>();
-            var rhs = other.GetSpan<byte>();
-            return lhs.SequenceEqual(rhs);
+            return Span.SequenceEqual(other.Span);
         }
     }
 }
diff --git a/csharp/src/Apache.Arrow/BitUtility.cs 
b/csharp/src/Apache.Arrow/BitUtility.cs
index ea5a556..3b4ee7a 100644
--- a/csharp/src/Apache.Arrow/BitUtility.cs
+++ b/csharp/src/Apache.Arrow/BitUtility.cs
@@ -20,8 +20,7 @@ namespace Apache.Arrow
 {
     public static class BitUtility
     {
-        private static readonly byte[] PopcountTable = new byte[]
-        {
+        private static readonly byte[] PopcountTable = {
             0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 
3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
             1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 
4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
             1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 
4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
@@ -32,8 +31,7 @@ namespace Apache.Arrow
             3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 
6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
         };
 
-        private static readonly byte[] BitMask = new byte[]
-        {
+        private static readonly byte[] BitMask = {
             1, 2, 4, 8, 16, 32, 64, 128
         };
 
diff --git a/csharp/src/Apache.Arrow/Bitmap.cs 
b/csharp/src/Apache.Arrow/Bitmap.cs
deleted file mode 100644
index 257438b..0000000
--- a/csharp/src/Apache.Arrow/Bitmap.cs
+++ /dev/null
@@ -1,75 +0,0 @@
-// 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.
-
-using Apache.Arrow.Memory;
-
-namespace Apache.Arrow
-{
-    public struct Bitmap
-    {
-        public ArrowBuffer Buffer { get; }
-
-        public int Length => Buffer.Size;
-
-        public Bitmap(ArrowBuffer buffer)
-        {
-            Buffer = buffer;
-        }
-
-        public static implicit operator Bitmap(ArrowBuffer buffer)
-        {
-            return new Bitmap(buffer);
-        }
-
-        public static implicit operator ArrowBuffer(Bitmap bitmap)
-        {
-            return bitmap.Buffer;
-        }
-
-        public static Bitmap Allocate(int bitCount, MemoryPool memoryPool = 
default)
-        {
-            var size = bitCount / 8 + (bitCount % 8 > 0 ? 1 : 0);
-            var remainder = size % 64;
-            var len = (remainder == 0) ? size : size + 64 - remainder;
-            
-            // Allocate buffer from memory pool and enable all bits
-
-            var buffer = ArrowBuffer.Allocate(len, memoryPool);
-            var span = buffer.GetSpan<byte>();
-
-            span.Fill(0xff);
-
-            return new Bitmap(buffer);
-        }
-
-        public void Clear(int index)
-        {
-            BitUtility.ClearBit(
-                Buffer.GetSpan<byte>(), index);
-        }
-
-        public void Set(int index)
-        {
-            BitUtility.SetBit(
-                Buffer.GetSpan<byte>(), index);
-        }
-
-        public bool IsSet(int index)
-        {
-            return BitUtility.GetBit(
-                Buffer.GetSpan<byte>(), index);
-        }
-    }
-}
diff --git a/csharp/src/Apache.Arrow/Types/DateType.cs 
b/csharp/src/Apache.Arrow/Extensions/SpanExtensions.cs
similarity index 67%
copy from csharp/src/Apache.Arrow/Types/DateType.cs
copy to csharp/src/Apache.Arrow/Extensions/SpanExtensions.cs
index 1fa2a32..b759f38 100644
--- a/csharp/src/Apache.Arrow/Types/DateType.cs
+++ b/csharp/src/Apache.Arrow/Extensions/SpanExtensions.cs
@@ -14,19 +14,18 @@
 // limitations under the License.
 
 using System;
-using System.Collections.Generic;
-using System.Text;
+using System.Runtime.InteropServices;
 
-namespace Apache.Arrow.Types
+namespace Apache.Arrow
 {
-    public enum DateUnit
+    public static class SpanExtensions
     {
-        Day = 0,
-        Milliseconds = 1
-    }
+        public static Span<T> CastTo<T>(this Span<byte> span)
+            where T: struct =>
+            MemoryMarshal.Cast<byte, T>(span);
 
-    public abstract class DateType: FixedWidthType
-    {
-        public abstract DateUnit Unit { get; }
+        public static ReadOnlySpan<T> CastTo<T>(this ReadOnlySpan<byte> span)
+            where T: struct =>
+                MemoryMarshal.Cast<byte, T>(span);
     }
 }
diff --git a/csharp/src/Apache.Arrow/Ipc/ArrowFileReader.cs 
b/csharp/src/Apache.Arrow/Ipc/ArrowFileReader.cs
index c47eab5..61c7627 100644
--- a/csharp/src/Apache.Arrow/Ipc/ArrowFileReader.cs
+++ b/csharp/src/Apache.Arrow/Ipc/ArrowFileReader.cs
@@ -13,14 +13,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+using FlatBuffers;
 using System;
-using System.Buffers;
 using System.Buffers.Binary;
 using System.IO;
-using System.Threading.Tasks;
-using FlatBuffers;
-using System.Threading;
 using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
 
 namespace Apache.Arrow.Ipc
 {
diff --git a/csharp/src/Apache.Arrow/Ipc/ArrowFileWriter.cs 
b/csharp/src/Apache.Arrow/Ipc/ArrowFileWriter.cs
index dac7b5b..98fbdf0 100644
--- a/csharp/src/Apache.Arrow/Ipc/ArrowFileWriter.cs
+++ b/csharp/src/Apache.Arrow/Ipc/ArrowFileWriter.cs
@@ -16,7 +16,6 @@
 using System;
 using System.Buffers.Binary;
 using System.Collections.Generic;
-using System.Diagnostics;
 using System.IO;
 using System.Threading;
 using System.Threading.Tasks;
@@ -38,6 +37,8 @@ namespace Apache.Arrow.Ipc
                 throw new ArgumentException("stream must be writable", 
nameof(stream));
             }
 
+            // TODO: Remove seek requirement
+
             if (!stream.CanSeek)
             {
                 throw new ArgumentException("stream must be seekable", 
nameof(stream));
@@ -66,7 +67,7 @@ namespace Apache.Arrow.Ipc
             RecordBatchBlocks.Add(block);
         }
 
-        public async Task CloseAsync(CancellationToken cancellationToken = 
default)
+        public async Task WriteFooterAsync(CancellationToken cancellationToken 
= default)
         {
             if (!HasWrittenFooter)
             {
@@ -77,19 +78,6 @@ namespace Apache.Arrow.Ipc
             await BaseStream.FlushAsync(cancellationToken);
         }
 
-        public override void Dispose()
-        {
-            try
-            {
-                CloseAsync().GetAwaiter().GetResult();
-            }
-            catch(Exception ex)
-            {
-                // NOTE: Dispose shouldn't throw.
-                Debug.WriteLine(ex);
-            }
-        }
-
         private async Task WriteHeaderAsync(CancellationToken 
cancellationToken)
         {
             cancellationToken.ThrowIfCancellationRequested();
@@ -144,10 +132,12 @@ namespace Apache.Arrow.Ipc
 
             cancellationToken.ThrowIfCancellationRequested();
 
-            Buffers.RentReturn(4, (buffer) =>
+            await Buffers.RentReturnAsync(4, async (buffer) =>
             {
                 BinaryPrimitives.WriteInt32LittleEndian(buffer,
                     Convert.ToInt32(BaseStream.Position - offset));
+
+                await BaseStream.WriteAsync(buffer, 0, 4, cancellationToken);
             });
 
             // Write magic
diff --git a/csharp/src/Apache.Arrow/Ipc/ArrowStreamReader.cs 
b/csharp/src/Apache.Arrow/Ipc/ArrowStreamReader.cs
index 18e254c..f6e1ca5 100644
--- a/csharp/src/Apache.Arrow/Ipc/ArrowStreamReader.cs
+++ b/csharp/src/Apache.Arrow/Ipc/ArrowStreamReader.cs
@@ -219,11 +219,14 @@ namespace Apache.Arrow.Ipc
         {
             if (buffer.Length <= 0)
             {
-                return null;
+                return ArrowBuffer.Empty;
             }
 
             var segment = bodyData.ToArraySegment((int)buffer.Offset, 
(int)buffer.Length);
-            return ArrowBuffer.FromMemory(segment);
+
+            return new ArrowBuffer.Builder<byte>(segment.Count)
+                .Append(segment)
+                .Build();
         }
 
         private static ArrayData LoadPrimitiveField(Field field,
diff --git a/csharp/src/Apache.Arrow/Ipc/ArrowStreamWriter.cs 
b/csharp/src/Apache.Arrow/Ipc/ArrowStreamWriter.cs
index 980a42d..639c64a 100644
--- a/csharp/src/Apache.Arrow/Ipc/ArrowStreamWriter.cs
+++ b/csharp/src/Apache.Arrow/Ipc/ArrowStreamWriter.cs
@@ -60,16 +60,15 @@ namespace Apache.Arrow.Ipc
             }
 
             private readonly List<Buffer> _buffers;
-            private int _offset;
 
             public IReadOnlyList<Buffer> Buffers => _buffers;
 
-            public int TotalLength => _offset;
+            public int TotalLength { get; private set; }
 
             public ArrowRecordBatchFlatBufferBuilder()
             {
                 _buffers = new List<Buffer>();
-                _offset = 0;
+                TotalLength = 0;
             }
 
             public void Visit(Int8Array array) => CreateBuffers(array);
@@ -113,16 +112,11 @@ namespace Apache.Arrow.Ipc
 
             private Buffer CreateBuffer(ArrowBuffer buffer)
             {
-                if (buffer == null)
-                {
-                    return new Buffer(null, _offset, 0);
-                }
-
-                var offset = _offset;
+                var offset = TotalLength;
 
-                _offset += buffer.Capacity;
+                TotalLength += buffer.Length;
 
-                return new Buffer(buffer, offset, buffer.Capacity);
+                return new Buffer(buffer, offset, buffer.Length);
             }
 
             public void Visit(IArrowArray array)
@@ -176,6 +170,8 @@ namespace Apache.Arrow.Ipc
         protected virtual async Task<Block> 
WriteRecordBatchInternalAsync(RecordBatch recordBatch,
             CancellationToken cancellationToken = default)
         {
+            // TODO: Truncate buffers with extraneous padding / unused capacity
+
             if (!HasWrittenSchema)
             {
                 await WriteSchemaAsync(Schema, cancellationToken);
@@ -243,10 +239,11 @@ namespace Apache.Arrow.Ipc
 
             for (var i = 0; i < buffers.Count; i++)
             {
-                if (buffers[i].DataBuffer == null)
+                if (buffers[i].DataBuffer.IsEmpty)
                     continue;
 
-                await buffers[i].DataBuffer.CopyToAsync(BaseStream, 
cancellationToken);
+                
+                await WriteBufferAsync(buffers[i].DataBuffer, 
cancellationToken);
             }
 
             // Write padding so the record batch message body length is a 
multiple of 8 bytes
@@ -257,7 +254,7 @@ namespace Apache.Arrow.Ipc
             await WritePaddingAsync(bodyPaddingLength);
 
             return new Block(
-                offset: Convert.ToInt32(metadataOffset), 
+                offset: Convert.ToInt32(metadataOffset),
                 length: bodyLength + bodyPaddingLength, 
                 metadataLength: Convert.ToInt32(metadataLength));
         }
@@ -266,6 +263,22 @@ namespace Apache.Arrow.Ipc
         {
             return WriteRecordBatchInternalAsync(recordBatch, 
cancellationToken);
         }
+    
+        public Task WriteBufferAsync(ArrowBuffer arrowBuffer, 
CancellationToken cancellationToken = default)
+        {
+            byte[] buffer = null;
+            try
+            {
+                var span = arrowBuffer.Span;
+                buffer = ArrayPool<byte>.Shared.Rent(span.Length);
+                span.CopyTo(buffer);
+                return BaseStream.WriteAsync(buffer, 0, buffer.Length, 
cancellationToken);
+            }
+            finally
+            {
+                ArrayPool<byte>.Shared.Return(buffer);
+            }
+        }
 
         protected Offset<Flatbuf.Schema> SerializeSchema(Schema schema)
         {
diff --git a/csharp/src/Apache.Arrow/Memory/DefaultMemoryPool.cs 
b/csharp/src/Apache.Arrow/Memory/DefaultMemoryPool.cs
deleted file mode 100644
index bf65979..0000000
--- a/csharp/src/Apache.Arrow/Memory/DefaultMemoryPool.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-// 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.
-
-using System;
-using System.Buffers;
-using System.Runtime.InteropServices;
-
-namespace Apache.Arrow.Memory
-{
-    public class DefaultMemoryPool
-    {
-        public const int DefaultAlignment = 64;
-        public const int DefaultPadding = 8;
-
-        public static readonly Lazy<MemoryPool> Instance = new 
Lazy<MemoryPool>(BuildDefault, true);
-
-        private static MemoryPool BuildDefault()
-        {
-            // TODO: Replace the default memory pool instance with a 
platform-specific implementation
-            // of memory pool with fallback to this implementation?
-
-            return new NativeMemoryPool(DefaultPadding, DefaultAlignment);
-        }
-
-    }
-}
diff --git a/csharp/src/Apache.Arrow/Memory/MemoryPool.cs 
b/csharp/src/Apache.Arrow/Memory/MemoryPool.cs
index 1e2c173..569ca74 100644
--- a/csharp/src/Apache.Arrow/Memory/MemoryPool.cs
+++ b/csharp/src/Apache.Arrow/Memory/MemoryPool.cs
@@ -21,6 +21,10 @@ namespace Apache.Arrow.Memory
 
     public abstract class MemoryPool
     {
+        public const int DefaultAlignment = 64;
+
+        public static Lazy<MemoryPool> Default { get; } = new 
Lazy<MemoryPool>(BuildDefault, true);
+
         public class Stats
         {
             private long _bytesAllocated;
@@ -38,9 +42,12 @@ namespace Apache.Arrow.Memory
 
         public Stats Statistics { get; }
 
-        protected MemoryPool()
+        protected int Alignment { get; }
+
+        protected MemoryPool(int alignment = DefaultAlignment)
         {
             Statistics = new Stats();
+            Alignment = alignment;
         }
 
         public Memory<byte> Allocate(int length)
@@ -50,14 +57,18 @@ namespace Apache.Arrow.Memory
                 throw new ArgumentOutOfRangeException(nameof(length));
             }
 
-            var bytesAllocated = 0;
-            var memory = AllocateInternal(length, out bytesAllocated);
+            if (length == 0)
+            {
+                return Memory<byte>.Empty;
+            }
+
+            var memory = AllocateInternal(length, out var bytesAllocated);
 
-            Statistics.Allocate(length);
+            Statistics.Allocate(bytesAllocated);
 
             // Ensure all allocated memory is zeroed.
 
-            ZeroMemory(memory);
+            ZeroMemory(memory.Span);
             
             return memory;
         }
@@ -69,18 +80,32 @@ namespace Apache.Arrow.Memory
                 throw new ArgumentOutOfRangeException(nameof(length));
             }
 
-            var bytesAllocated = 0;
-            var buffer = ReallocateInternal(memory, length, out 
bytesAllocated);
+            if (length == 0)
+            {
+                return Memory<byte>.Empty;
+            }
+
+            var buffer = ReallocateInternal(memory, length, out var 
bytesAllocated);
 
             Statistics.Allocate(bytesAllocated);
 
+            if (length > memory.Length)
+            {
+                ZeroMemory(buffer.Span.Slice(
+                    memory.Length, length - memory.Length));
+            }
+
             return buffer;
+        }
 
+        private static void ZeroMemory(Span<byte> span)
+        {
+            span.Fill(0);
         }
 
-        private static void ZeroMemory(Memory<byte> memory)
+        private static MemoryPool BuildDefault()
         {
-            memory.Span.Fill(0);
+            return new NativeMemoryPool(DefaultAlignment);
         }
 
         protected abstract Memory<byte> AllocateInternal(int length, out int 
bytesAllocated);
diff --git a/csharp/src/Apache.Arrow/Memory/NativeMemory.cs 
b/csharp/src/Apache.Arrow/Memory/NativeMemory.cs
index c5e29aa..a188f45 100644
--- a/csharp/src/Apache.Arrow/Memory/NativeMemory.cs
+++ b/csharp/src/Apache.Arrow/Memory/NativeMemory.cs
@@ -25,8 +25,8 @@ namespace Apache.Arrow.Memory
     public class NativeMemoryManager: MemoryManager<byte>
     {
         private IntPtr _ptr;
-        private int _offset;
-        private int _length;
+        private readonly int _offset;
+        private readonly int _length;
 
         public NativeMemoryManager(IntPtr ptr, int offset, int length)
         {
@@ -40,13 +40,13 @@ namespace Apache.Arrow.Memory
             Dispose(false);
         }
 
-        public unsafe override Span<byte> GetSpan()
+        public override unsafe Span<byte> GetSpan()
         {
             var ptr = CalculatePointer(0);
             return new Span<byte>(ptr, _length);
         }
 
-        public unsafe override MemoryHandle Pin(int elementIndex = 0)
+        public override unsafe MemoryHandle Pin(int elementIndex = 0)
         {
             // NOTE: Unmanaged memory doesn't require GC pinning because by 
definition it's not
             // managed by the garbage collector.
diff --git a/csharp/src/Apache.Arrow/Memory/NativeMemoryPool.cs 
b/csharp/src/Apache.Arrow/Memory/NativeMemoryPool.cs
index 9413951..2ea07ce 100644
--- a/csharp/src/Apache.Arrow/Memory/NativeMemoryPool.cs
+++ b/csharp/src/Apache.Arrow/Memory/NativeMemoryPool.cs
@@ -20,19 +20,8 @@ namespace Apache.Arrow.Memory
 {
     public class NativeMemoryPool : MemoryPool
     {
-        private readonly int _padding;
-        private readonly int _alignment;
-
-        public NativeMemoryPool(int padding, int alignment)
-        {
-            if (padding < 0) throw new 
ArgumentOutOfRangeException(nameof(padding));
-            if (alignment < 0) throw new 
ArgumentOutOfRangeException(nameof(alignment));
-            
-            // TODO: Ensure alignment is a power of two.
-
-            _padding = padding;
-            _alignment = alignment;
-        }
+        public NativeMemoryPool(int alignment = DefaultAlignment) 
+            : base(alignment) { }
 
         protected override Memory<byte> AllocateInternal(int length, out int 
bytesAllocated)
         {
@@ -42,14 +31,13 @@ namespace Apache.Arrow.Memory
             // to allocated memory, offset, and the allocation size. 
 
             // TODO: Should the allocation be moved to NativeMemory?
-            
-            var size = BitUtility.RoundUpToMultiplePowerOfTwo(length, 
_padding);
-            var ptr =  Marshal.AllocHGlobal(size + _alignment);
-            var offset = (int)(_alignment - (ptr.ToInt64() & (_alignment - 
1)));
-            
-            var manager = new NativeMemoryManager(ptr, offset, size);
 
-            bytesAllocated = (size + _alignment);
+            var size = length + Alignment;
+            var ptr =  Marshal.AllocHGlobal(size);
+            var offset = (int)(Alignment - (ptr.ToInt64() & (Alignment - 1)));
+            var manager = new NativeMemoryManager(ptr, offset, length);
+
+            bytesAllocated = (length + Alignment);
 
             GC.AddMemoryPressure(bytesAllocated);
 
diff --git a/csharp/src/Apache.Arrow/Types/ArrowType.cs 
b/csharp/src/Apache.Arrow/Types/ArrowType.cs
index 9e4b360..c0eca23 100644
--- a/csharp/src/Apache.Arrow/Types/ArrowType.cs
+++ b/csharp/src/Apache.Arrow/Types/ArrowType.cs
@@ -13,6 +13,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+
 namespace Apache.Arrow.Types
 {
     public abstract class ArrowType: IArrowType
@@ -24,5 +25,19 @@ namespace Apache.Arrow.Types
         public virtual bool IsFixedWidth => false;
 
         public abstract void Accept(IArrowTypeVisitor visitor);
+
+        internal static void Accept<T>(T type, IArrowTypeVisitor visitor)
+            where T: class, IArrowType
+        {
+            switch (visitor)
+            {
+                case IArrowTypeVisitor<T> typedVisitor:
+                    typedVisitor.Visit(type);
+                    break;
+                default:
+                    visitor.Visit(type);
+                    break;
+            }
+        }
     }
 }
diff --git a/csharp/src/Apache.Arrow/Types/BinaryType.cs 
b/csharp/src/Apache.Arrow/Types/BinaryType.cs
index 8ae7533..6734d93 100644
--- a/csharp/src/Apache.Arrow/Types/BinaryType.cs
+++ b/csharp/src/Apache.Arrow/Types/BinaryType.cs
@@ -13,9 +13,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-using System;
-using System.Collections.Generic;
-using System.Text;
 
 namespace Apache.Arrow.Types
 {
@@ -26,10 +23,6 @@ namespace Apache.Arrow.Types
         public override ArrowTypeId TypeId => ArrowTypeId.Binary;
         public override string Name => "binary";
 
-        public override void Accept(IArrowTypeVisitor visitor)
-        {
-            if (visitor is IArrowTypeVisitor<BinaryType> v)
-                v.Visit(this);
-        }
+        public override void Accept(IArrowTypeVisitor visitor) => Accept(this, 
visitor);
     }
 }
diff --git a/csharp/src/Apache.Arrow/Types/BooleanType.cs 
b/csharp/src/Apache.Arrow/Types/BooleanType.cs
index 5a26c87..3b57414 100644
--- a/csharp/src/Apache.Arrow/Types/BooleanType.cs
+++ b/csharp/src/Apache.Arrow/Types/BooleanType.cs
@@ -13,13 +13,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-using System;
-using System.Collections.Generic;
-using System.Text;
 
 namespace Apache.Arrow.Types
 {
-    public class BooleanType: NumberType
+    public sealed class BooleanType: NumberType
     {
         public static readonly BooleanType Default = new BooleanType();
 
@@ -28,10 +25,6 @@ namespace Apache.Arrow.Types
         public override int BitWidth => 1;
         public override bool IsSigned => false;
 
-        public override void Accept(IArrowTypeVisitor visitor)
-        {
-            if (visitor is IArrowTypeVisitor<Int8Type> v)
-                v.Visit(this);
-        }
+        public override void Accept(IArrowTypeVisitor visitor) => Accept(this, 
visitor);
     }
 }
diff --git a/csharp/src/Apache.Arrow/Types/Date32Type.cs 
b/csharp/src/Apache.Arrow/Types/Date32Type.cs
index 19e6823..9673bf6 100644
--- a/csharp/src/Apache.Arrow/Types/Date32Type.cs
+++ b/csharp/src/Apache.Arrow/Types/Date32Type.cs
@@ -13,13 +13,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-using System;
-using System.Collections.Generic;
-using System.Text;
 
 namespace Apache.Arrow.Types
 {
-    public class Date32Type: DateType
+    public sealed class Date32Type: DateType
     {
         public static readonly Date32Type Default = new Date32Type();
 
@@ -28,10 +25,6 @@ namespace Apache.Arrow.Types
         public override int BitWidth => 32;
         public override DateUnit Unit => DateUnit.Day;
 
-        public override void Accept(IArrowTypeVisitor visitor)
-        {
-            if (visitor is IArrowTypeVisitor<Date32Type> v)
-                v.Visit(this);
-        }
+        public override void Accept(IArrowTypeVisitor visitor) => Accept(this, 
visitor);
     }
 }
diff --git a/csharp/src/Apache.Arrow/Types/Date64Type.cs 
b/csharp/src/Apache.Arrow/Types/Date64Type.cs
index d301ca4..2a9e1aa 100644
--- a/csharp/src/Apache.Arrow/Types/Date64Type.cs
+++ b/csharp/src/Apache.Arrow/Types/Date64Type.cs
@@ -13,13 +13,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-using System;
-using System.Collections.Generic;
-using System.Text;
 
 namespace Apache.Arrow.Types
 {
-    public class Date64Type: DateType
+    public sealed class Date64Type : DateType
     {
         public static readonly Date64Type Default = new Date64Type();
 
@@ -28,10 +25,6 @@ namespace Apache.Arrow.Types
         public override int BitWidth => 64;
         public override DateUnit Unit => DateUnit.Milliseconds;
 
-        public override void Accept(IArrowTypeVisitor visitor)
-        {
-            if (visitor is IArrowTypeVisitor<Date64Type> v)
-                v.Visit(this);
-        }
+        public override void Accept(IArrowTypeVisitor visitor) => Accept(this, 
visitor);
     }
 }
diff --git a/csharp/src/Apache.Arrow/Types/DateType.cs 
b/csharp/src/Apache.Arrow/Types/DateType.cs
index 1fa2a32..8f15b08 100644
--- a/csharp/src/Apache.Arrow/Types/DateType.cs
+++ b/csharp/src/Apache.Arrow/Types/DateType.cs
@@ -13,9 +13,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-using System;
-using System.Collections.Generic;
-using System.Text;
 
 namespace Apache.Arrow.Types
 {
diff --git a/csharp/src/Apache.Arrow/Types/DecimalType.cs 
b/csharp/src/Apache.Arrow/Types/DecimalType.cs
index adb9a06..cad2e24 100644
--- a/csharp/src/Apache.Arrow/Types/DecimalType.cs
+++ b/csharp/src/Apache.Arrow/Types/DecimalType.cs
@@ -15,7 +15,7 @@
 
 namespace Apache.Arrow.Types
 {
-    public class DecimalType: FixedSizeBinaryType
+    public sealed class DecimalType: FixedSizeBinaryType
     {
         public override ArrowTypeId TypeId => ArrowTypeId.Decimal;
         public override string Name => "decimal";
diff --git a/csharp/src/Apache.Arrow/Types/DoubleType.cs 
b/csharp/src/Apache.Arrow/Types/DoubleType.cs
index 9fb0969..aa6ade6 100644
--- a/csharp/src/Apache.Arrow/Types/DoubleType.cs
+++ b/csharp/src/Apache.Arrow/Types/DoubleType.cs
@@ -13,13 +13,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-using System;
-using System.Collections.Generic;
-using System.Text;
 
 namespace Apache.Arrow.Types
 {
-    public class DoubleType: FloatingPointType
+    public sealed class DoubleType: FloatingPointType
     {
         public static readonly DoubleType Default = new DoubleType();
 
@@ -29,10 +26,6 @@ namespace Apache.Arrow.Types
         public override bool IsSigned => true;
         public override PrecisionKind Precision => PrecisionKind.Double;
 
-        public override void Accept(IArrowTypeVisitor visitor)
-        {
-            if (visitor is IArrowTypeVisitor<DoubleType> v)
-                v.Visit(this);
-        }
+        public override void Accept(IArrowTypeVisitor visitor) => Accept(this, 
visitor);
     }
 }
diff --git a/csharp/src/Apache.Arrow/Types/FixedSizeBinaryType.cs 
b/csharp/src/Apache.Arrow/Types/FixedSizeBinaryType.cs
index 6e16730..ccbfc8c 100644
--- a/csharp/src/Apache.Arrow/Types/FixedSizeBinaryType.cs
+++ b/csharp/src/Apache.Arrow/Types/FixedSizeBinaryType.cs
@@ -14,12 +14,10 @@
 // limitations under the License.
 
 using System;
-using System.Collections.Generic;
-using System.Text;
 
 namespace Apache.Arrow.Types
 {
-    public class FixedSizeBinaryType: FixedWidthType
+    public class FixedSizeBinaryType : FixedWidthType
     {
         public override ArrowTypeId TypeId => ArrowTypeId.FixedSizedBinary;
         public override string Name => "fixed_size_binary";
@@ -34,12 +32,7 @@ namespace Apache.Arrow.Types
             ByteWidth = byteWidth;
         }
 
-        public override void Accept(IArrowTypeVisitor visitor)
-        {
-            if (visitor is IArrowTypeVisitor<FixedSizeBinaryType> v)
-                v.Visit(this);
-        }
+        public override void Accept(IArrowTypeVisitor visitor) => Accept(this, 
visitor);
 
-        
     }
 }
diff --git a/csharp/src/Apache.Arrow/Types/FixedWidthType.cs 
b/csharp/src/Apache.Arrow/Types/FixedWidthType.cs
index 72b46a2..d1c9e8c 100644
--- a/csharp/src/Apache.Arrow/Types/FixedWidthType.cs
+++ b/csharp/src/Apache.Arrow/Types/FixedWidthType.cs
@@ -13,9 +13,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-using System;
-using System.Collections.Generic;
-using System.Text;
 
 namespace Apache.Arrow.Types
 {
diff --git a/csharp/src/Apache.Arrow/Types/FloatType.cs 
b/csharp/src/Apache.Arrow/Types/FloatType.cs
index c423293..a3f7b39 100644
--- a/csharp/src/Apache.Arrow/Types/FloatType.cs
+++ b/csharp/src/Apache.Arrow/Types/FloatType.cs
@@ -13,13 +13,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-using System;
-using System.Collections.Generic;
-using System.Text;
 
 namespace Apache.Arrow.Types
 {
-    public class FloatType: FloatingPointType
+    public sealed class FloatType: FloatingPointType
     {
         public static readonly FloatType Default = new FloatType();
 
@@ -29,10 +26,6 @@ namespace Apache.Arrow.Types
         public override bool IsSigned => true;
         public override PrecisionKind Precision => PrecisionKind.Single;
 
-        public override void Accept(IArrowTypeVisitor visitor)
-        {
-            if (visitor is IArrowTypeVisitor<FloatType> v)
-                v.Visit(this);
-        }
+        public override void Accept(IArrowTypeVisitor visitor) => Accept(this, 
visitor);
     }
 }
diff --git a/csharp/src/Apache.Arrow/Types/FloatingPointType.cs 
b/csharp/src/Apache.Arrow/Types/FloatingPointType.cs
index 5f667c7..9fbe43a 100644
--- a/csharp/src/Apache.Arrow/Types/FloatingPointType.cs
+++ b/csharp/src/Apache.Arrow/Types/FloatingPointType.cs
@@ -13,9 +13,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-using System;
-using System.Collections.Generic;
-using System.Text;
 
 namespace Apache.Arrow.Types
 {
diff --git a/csharp/src/Apache.Arrow/Types/HalfFloatType.cs 
b/csharp/src/Apache.Arrow/Types/HalfFloatType.cs
index 22f1370..5bfa232 100644
--- a/csharp/src/Apache.Arrow/Types/HalfFloatType.cs
+++ b/csharp/src/Apache.Arrow/Types/HalfFloatType.cs
@@ -13,13 +13,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-using System;
-using System.Collections.Generic;
-using System.Text;
 
 namespace Apache.Arrow.Types
 {
-    public class HalfFloatType: FloatingPointType
+    public sealed class HalfFloatType: FloatingPointType
     {
         public static readonly HalfFloatType Default = new HalfFloatType();
 
@@ -29,10 +26,6 @@ namespace Apache.Arrow.Types
         public override bool IsSigned => true;
         public override PrecisionKind Precision => PrecisionKind.Half;
 
-        public override void Accept(IArrowTypeVisitor visitor)
-        {
-            if (visitor is IArrowTypeVisitor<HalfFloatType> v)
-                v.Visit(this);
-        }
+        public override void Accept(IArrowTypeVisitor visitor) => Accept(this, 
visitor);
     }
 }
diff --git a/csharp/src/Apache.Arrow/Types/IArrowType.cs 
b/csharp/src/Apache.Arrow/Types/IArrowType.cs
index d75be54..578e18b 100644
--- a/csharp/src/Apache.Arrow/Types/IArrowType.cs
+++ b/csharp/src/Apache.Arrow/Types/IArrowType.cs
@@ -13,9 +13,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-using System;
-using System.Collections.Generic;
-using System.Text;
 
 namespace Apache.Arrow.Types
 {
diff --git a/csharp/src/Apache.Arrow/Types/IArrowTypeVisitor.cs 
b/csharp/src/Apache.Arrow/Types/IArrowTypeVisitor.cs
index 3cd602b..ce5b114 100644
--- a/csharp/src/Apache.Arrow/Types/IArrowTypeVisitor.cs
+++ b/csharp/src/Apache.Arrow/Types/IArrowTypeVisitor.cs
@@ -13,9 +13,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-using System;
-using System.Collections.Generic;
-using System.Text;
 
 namespace Apache.Arrow.Types
 {
diff --git a/csharp/src/Apache.Arrow/Types/Int16Type.cs 
b/csharp/src/Apache.Arrow/Types/Int16Type.cs
index 3a7edbe..f1d6868 100644
--- a/csharp/src/Apache.Arrow/Types/Int16Type.cs
+++ b/csharp/src/Apache.Arrow/Types/Int16Type.cs
@@ -15,7 +15,7 @@
 
 namespace Apache.Arrow.Types
 {
-    public class Int16Type : NumberType
+    public sealed class Int16Type : NumberType
     {
         public static readonly Int16Type Default = new Int16Type();
 
@@ -24,10 +24,6 @@ namespace Apache.Arrow.Types
         public override int BitWidth => 16;
         public override bool IsSigned => true;
 
-        public override void Accept(IArrowTypeVisitor visitor)
-        {
-            if (visitor is IArrowTypeVisitor<Int16Type> v)
-                v.Visit(this);
-        }
+        public override void Accept(IArrowTypeVisitor visitor) => Accept(this, 
visitor);
     }
 }
\ No newline at end of file
diff --git a/csharp/src/Apache.Arrow/Types/Int32Type.cs 
b/csharp/src/Apache.Arrow/Types/Int32Type.cs
index e8df522..a32c884 100644
--- a/csharp/src/Apache.Arrow/Types/Int32Type.cs
+++ b/csharp/src/Apache.Arrow/Types/Int32Type.cs
@@ -15,7 +15,7 @@
 
 namespace Apache.Arrow.Types
 {
-    public class Int32Type : NumberType
+    public sealed class Int32Type : NumberType
     {
         public static readonly Int32Type Default = new Int32Type();
 
@@ -24,10 +24,6 @@ namespace Apache.Arrow.Types
         public override int BitWidth => 32;
         public override bool IsSigned => true;
 
-        public override void Accept(IArrowTypeVisitor visitor)
-        {
-            if (visitor is IArrowTypeVisitor<Int32Type> v)
-                v.Visit(this);
-        }
+        public override void Accept(IArrowTypeVisitor visitor) => Accept(this, 
visitor);
     }
 }
\ No newline at end of file
diff --git a/csharp/src/Apache.Arrow/Types/Int64Type.cs 
b/csharp/src/Apache.Arrow/Types/Int64Type.cs
index afdf409..f45523c 100644
--- a/csharp/src/Apache.Arrow/Types/Int64Type.cs
+++ b/csharp/src/Apache.Arrow/Types/Int64Type.cs
@@ -15,7 +15,7 @@
 
 namespace Apache.Arrow.Types
 {
-    public class Int64Type : NumberType
+    public sealed class Int64Type : NumberType
     {
         public static readonly Int64Type Default = new Int64Type();
 
@@ -24,10 +24,6 @@ namespace Apache.Arrow.Types
         public override int BitWidth => 64;
         public override bool IsSigned => true;
 
-        public override void Accept(IArrowTypeVisitor visitor)
-        {
-            if (visitor is IArrowTypeVisitor<Int64Type> v)
-                v.Visit(this);
-        }
+        public override void Accept(IArrowTypeVisitor visitor) => Accept(this, 
visitor);
     }
 }
\ No newline at end of file
diff --git a/csharp/src/Apache.Arrow/Types/Int8Type.cs 
b/csharp/src/Apache.Arrow/Types/Int8Type.cs
index 9687cd3..9b3f5b5 100644
--- a/csharp/src/Apache.Arrow/Types/Int8Type.cs
+++ b/csharp/src/Apache.Arrow/Types/Int8Type.cs
@@ -13,13 +13,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-using System;
-using System.Collections.Generic;
-using System.Text;
 
 namespace Apache.Arrow.Types
 {
-    public class Int8Type: NumberType
+    public sealed class Int8Type : NumberType
     {
         public static readonly Int8Type Default = new Int8Type();
 
@@ -28,10 +25,6 @@ namespace Apache.Arrow.Types
         public override int BitWidth => 8;
         public override bool IsSigned => true;
 
-        public override void Accept(IArrowTypeVisitor visitor)
-        {
-            if (visitor is IArrowTypeVisitor<Int8Type> v)
-                v.Visit(this);
-        }
+        public override void Accept(IArrowTypeVisitor visitor) => Accept(this, 
visitor);
     }
 }
diff --git a/csharp/src/Apache.Arrow/Types/IntervalUnit.cs 
b/csharp/src/Apache.Arrow/Types/IntervalUnit.cs
index e287548..6dda0cf 100644
--- a/csharp/src/Apache.Arrow/Types/IntervalUnit.cs
+++ b/csharp/src/Apache.Arrow/Types/IntervalUnit.cs
@@ -13,9 +13,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-using System;
-using System.Collections.Generic;
-using System.Text;
 
 namespace Apache.Arrow.Types
 {
@@ -25,7 +22,7 @@ namespace Apache.Arrow.Types
         DayTime = 1
     }
 
-    public class IntervalType: FixedWidthType
+    public sealed class IntervalType : FixedWidthType
     {
         public override ArrowTypeId TypeId => ArrowTypeId.Interval;
         public override string Name => "date";
@@ -38,10 +35,6 @@ namespace Apache.Arrow.Types
             Unit = unit;
         }
 
-        public override void Accept(IArrowTypeVisitor visitor)
-        {
-            if (visitor is IArrowTypeVisitor<IntervalType> v)
-                v.Visit(this);
-        }
+        public override void Accept(IArrowTypeVisitor visitor) => Accept(this, 
visitor);
     }
 }
diff --git a/csharp/src/Apache.Arrow/Types/ListType.cs 
b/csharp/src/Apache.Arrow/Types/ListType.cs
index fa5c87c..5d48a61 100644
--- a/csharp/src/Apache.Arrow/Types/ListType.cs
+++ b/csharp/src/Apache.Arrow/Types/ListType.cs
@@ -14,12 +14,10 @@
 // limitations under the License.
 
 using System;
-using System.Collections.Generic;
-using System.Text;
 
 namespace Apache.Arrow.Types
 {
-    public class ListType: ArrowType
+    public sealed class ListType : ArrowType
     {
         public override ArrowTypeId TypeId => ArrowTypeId.List;
         public override string Name => "list";
@@ -33,10 +31,6 @@ namespace Apache.Arrow.Types
             ValueDataType = valueDataType ?? NullType.Default;
         }
 
-        public override void Accept(IArrowTypeVisitor visitor)
-        {
-            if (visitor is IArrowTypeVisitor<ListType> v)
-                v.Visit(this);
-        }
+        public override void Accept(IArrowTypeVisitor visitor) => Accept(this, 
visitor);
     }
 }
diff --git a/csharp/src/Apache.Arrow/Types/NullType.cs 
b/csharp/src/Apache.Arrow/Types/NullType.cs
index b299ed8..4afe1dc 100644
--- a/csharp/src/Apache.Arrow/Types/NullType.cs
+++ b/csharp/src/Apache.Arrow/Types/NullType.cs
@@ -13,23 +13,16 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-using System;
-using System.Collections.Generic;
-using System.Text;
 
 namespace Apache.Arrow.Types
 {
-    public class NullType: ArrowType
+    public sealed class NullType : ArrowType
     {
         public static readonly NullType Default = new NullType();
 
         public override ArrowTypeId TypeId => ArrowTypeId.Null;
         public override string Name => "null";
 
-        public override void Accept(IArrowTypeVisitor visitor)
-        {
-            if (visitor is IArrowTypeVisitor<NullType> v)
-                v.Visit(this);
-        }
+        public override void Accept(IArrowTypeVisitor visitor) => Accept(this, 
visitor);
     }
 }
diff --git a/csharp/src/Apache.Arrow/Types/NumberType.cs 
b/csharp/src/Apache.Arrow/Types/NumberType.cs
index a80bd44..04d21bc 100644
--- a/csharp/src/Apache.Arrow/Types/NumberType.cs
+++ b/csharp/src/Apache.Arrow/Types/NumberType.cs
@@ -13,9 +13,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-using System;
-using System.Collections.Generic;
-using System.Text;
 
 namespace Apache.Arrow.Types
 {
diff --git a/csharp/src/Apache.Arrow/Types/StringType.cs 
b/csharp/src/Apache.Arrow/Types/StringType.cs
index f2bb082..33620aa 100644
--- a/csharp/src/Apache.Arrow/Types/StringType.cs
+++ b/csharp/src/Apache.Arrow/Types/StringType.cs
@@ -13,23 +13,16 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-using System;
-using System.Collections.Generic;
-using System.Text;
 
 namespace Apache.Arrow.Types
 {
-    public class StringType: ArrowType
+    public sealed class StringType : ArrowType
     {
         public static StringType Default = new StringType();
 
         public override ArrowTypeId TypeId => ArrowTypeId.String;
         public override string Name => "utf8";
 
-        public override void Accept(IArrowTypeVisitor visitor)
-        {
-            if (visitor is IArrowTypeVisitor<StringType> v)
-                v.Visit(this);
-        }
+        public override void Accept(IArrowTypeVisitor visitor) => Accept(this, 
visitor);
     }
 }
diff --git a/csharp/src/Apache.Arrow/Types/StructType.cs 
b/csharp/src/Apache.Arrow/Types/StructType.cs
index f9b9e0c..fb074c1 100644
--- a/csharp/src/Apache.Arrow/Types/StructType.cs
+++ b/csharp/src/Apache.Arrow/Types/StructType.cs
@@ -19,7 +19,7 @@ using System.Linq;
 
 namespace Apache.Arrow.Types
 {
-    public class StructType: ArrowType
+    public sealed class StructType : ArrowType
     {
         private readonly List<Field> _fields;
 
@@ -55,10 +55,6 @@ namespace Apache.Arrow.Types
                 field => comparer.Equals(field.Name, name));
         }
 
-        public override void Accept(IArrowTypeVisitor visitor)
-        {
-            if (visitor is IArrowTypeVisitor<StructType> v)
-                v.Visit(this);
-        }
+        public override void Accept(IArrowTypeVisitor visitor) => Accept(this, 
visitor);
     }
 }
diff --git a/csharp/src/Apache.Arrow/Types/Time32Type.cs 
b/csharp/src/Apache.Arrow/Types/Time32Type.cs
index 70cfe50..99c409b 100644
--- a/csharp/src/Apache.Arrow/Types/Time32Type.cs
+++ b/csharp/src/Apache.Arrow/Types/Time32Type.cs
@@ -13,13 +13,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-using System;
-using System.Collections.Generic;
-using System.Text;
 
 namespace Apache.Arrow.Types
 {
-    public class Time32Type: TimeType
+    public sealed class Time32Type : TimeType
     {
         public static readonly Time32Type Default = new Time32Type();
 
@@ -30,10 +27,6 @@ namespace Apache.Arrow.Types
         public Time32Type(TimeUnit unit = TimeUnit.Millisecond)
             : base(unit) { }
 
-        public override void Accept(IArrowTypeVisitor visitor)
-        {
-            if (visitor is IArrowTypeVisitor<Int16Type> v)
-                v.Visit(this);
-        }
+        public override void Accept(IArrowTypeVisitor visitor) => Accept(this, 
visitor);
     }
 }
diff --git a/csharp/src/Apache.Arrow/Types/Time64Type.cs 
b/csharp/src/Apache.Arrow/Types/Time64Type.cs
index 3f72785..5d6c2e4 100644
--- a/csharp/src/Apache.Arrow/Types/Time64Type.cs
+++ b/csharp/src/Apache.Arrow/Types/Time64Type.cs
@@ -13,13 +13,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-using System;
-using System.Collections.Generic;
-using System.Text;
 
 namespace Apache.Arrow.Types
 {
-    public class Time64Type: TimeType
+    public sealed class Time64Type : TimeType
     {
         public static readonly Time64Type Default = new Time64Type();
 
@@ -30,10 +27,6 @@ namespace Apache.Arrow.Types
         public Time64Type(TimeUnit unit = TimeUnit.Millisecond)
             : base(unit) { }
 
-        public override void Accept(IArrowTypeVisitor visitor)
-        {
-            if (visitor is IArrowTypeVisitor<Time64Type> v)
-                v.Visit(this);
-        }
+        public override void Accept(IArrowTypeVisitor visitor) => Accept(this, 
visitor);
     }
 }
diff --git a/csharp/src/Apache.Arrow/Types/TimeType.cs 
b/csharp/src/Apache.Arrow/Types/TimeType.cs
index dba488b..9afa3fb 100644
--- a/csharp/src/Apache.Arrow/Types/TimeType.cs
+++ b/csharp/src/Apache.Arrow/Types/TimeType.cs
@@ -13,9 +13,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-using System;
-using System.Collections.Generic;
-using System.Text;
 
 namespace Apache.Arrow.Types
 {
diff --git a/csharp/src/Apache.Arrow/Types/TimestampType.cs 
b/csharp/src/Apache.Arrow/Types/TimestampType.cs
index 22da832..4137818 100644
--- a/csharp/src/Apache.Arrow/Types/TimestampType.cs
+++ b/csharp/src/Apache.Arrow/Types/TimestampType.cs
@@ -13,13 +13,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-using System;
-using System.Collections.Generic;
-using System.Text;
 
 namespace Apache.Arrow.Types
 {
-    public class TimestampType: FixedWidthType
+    public sealed class TimestampType : FixedWidthType
     {
         public static readonly TimestampType Default = new 
TimestampType(TimeUnit.Millisecond, "UTC");
 
@@ -38,10 +35,6 @@ namespace Apache.Arrow.Types
             Timezone = timezone;
         }
 
-        public override void Accept(IArrowTypeVisitor visitor)
-        {
-            if (visitor is IArrowTypeVisitor<TimestampType> v)
-                v.Visit(this);
-        }
+        public override void Accept(IArrowTypeVisitor visitor) => Accept(this, 
visitor);
     }
 }
diff --git a/csharp/src/Apache.Arrow/Types/UInt16Type.cs 
b/csharp/src/Apache.Arrow/Types/UInt16Type.cs
index eb87729..1925ffb 100644
--- a/csharp/src/Apache.Arrow/Types/UInt16Type.cs
+++ b/csharp/src/Apache.Arrow/Types/UInt16Type.cs
@@ -15,7 +15,7 @@
 
 namespace Apache.Arrow.Types
 {
-    public class UInt16Type : NumberType
+    public sealed class UInt16Type : NumberType
     {
         public static readonly UInt16Type Default = new UInt16Type();
 
@@ -24,10 +24,6 @@ namespace Apache.Arrow.Types
         public override int BitWidth => 16;
         public override bool IsSigned => false;
 
-        public override void Accept(IArrowTypeVisitor visitor)
-        {
-            if (visitor is IArrowTypeVisitor<UInt16Type> v)
-                v.Visit(this);
-        }
+        public override void Accept(IArrowTypeVisitor visitor) => Accept(this, 
visitor);
     }
 }
\ No newline at end of file
diff --git a/csharp/src/Apache.Arrow/Types/UInt32Type.cs 
b/csharp/src/Apache.Arrow/Types/UInt32Type.cs
index e520004..8007025 100644
--- a/csharp/src/Apache.Arrow/Types/UInt32Type.cs
+++ b/csharp/src/Apache.Arrow/Types/UInt32Type.cs
@@ -15,7 +15,7 @@
 
 namespace Apache.Arrow.Types
 {
-    public class UInt32Type : NumberType
+    public sealed class UInt32Type : NumberType
     {
         public static readonly UInt32Type Default = new UInt32Type();
 
@@ -24,10 +24,6 @@ namespace Apache.Arrow.Types
         public override int BitWidth => 32;
         public override bool IsSigned => false;
 
-        public override void Accept(IArrowTypeVisitor visitor)
-        {
-            if (visitor is IArrowTypeVisitor<UInt32Type> v)
-                v.Visit(this);
-        }
+        public override void Accept(IArrowTypeVisitor visitor) => Accept(this, 
visitor);
     }
 }
\ No newline at end of file
diff --git a/csharp/src/Apache.Arrow/Types/UInt64Type.cs 
b/csharp/src/Apache.Arrow/Types/UInt64Type.cs
index 45c6fac..20b51ad 100644
--- a/csharp/src/Apache.Arrow/Types/UInt64Type.cs
+++ b/csharp/src/Apache.Arrow/Types/UInt64Type.cs
@@ -15,7 +15,7 @@
 
 namespace Apache.Arrow.Types
 {
-    public class UInt64Type : NumberType
+    public sealed class UInt64Type : NumberType
     {
         public static readonly UInt64Type Default = new UInt64Type();
 
@@ -24,10 +24,6 @@ namespace Apache.Arrow.Types
         public override int BitWidth => 64;
         public override bool IsSigned => false;
 
-        public override void Accept(IArrowTypeVisitor visitor)
-        {
-            if (visitor is IArrowTypeVisitor<UInt64Type> v)
-                v.Visit(this);
-        }
+        public override void Accept(IArrowTypeVisitor visitor) => Accept(this, 
visitor);
     }
 }
\ No newline at end of file
diff --git a/csharp/src/Apache.Arrow/Types/UInt8Type.cs 
b/csharp/src/Apache.Arrow/Types/UInt8Type.cs
index d63e42b..e2e5365 100644
--- a/csharp/src/Apache.Arrow/Types/UInt8Type.cs
+++ b/csharp/src/Apache.Arrow/Types/UInt8Type.cs
@@ -15,7 +15,7 @@
 
 namespace Apache.Arrow.Types
 {
-    public class UInt8Type : NumberType
+    public sealed class UInt8Type : NumberType
     {
         public static readonly UInt8Type Default = new UInt8Type();
 
@@ -24,10 +24,6 @@ namespace Apache.Arrow.Types
         public override int BitWidth => 8;
         public override bool IsSigned => false;
 
-        public override void Accept(IArrowTypeVisitor visitor)
-        {
-            if (visitor is IArrowTypeVisitor<Int8Type> v)
-                v.Visit(this);
-        }
+        public override void Accept(IArrowTypeVisitor visitor) => Accept(this, 
visitor);
     }
 }
\ No newline at end of file
diff --git a/csharp/src/Apache.Arrow/Types/UnionType.cs 
b/csharp/src/Apache.Arrow/Types/UnionType.cs
index aadb1e7..2932710 100644
--- a/csharp/src/Apache.Arrow/Types/UnionType.cs
+++ b/csharp/src/Apache.Arrow/Types/UnionType.cs
@@ -24,7 +24,7 @@ namespace Apache.Arrow.Types
         Dense
     }
 
-    public class UnionType: ArrowType
+    public sealed class UnionType : ArrowType
     {
         public override ArrowTypeId TypeId => ArrowTypeId.Union;
         public override string Name => "union";
@@ -41,10 +41,6 @@ namespace Apache.Arrow.Types
             Mode = mode;
         }
 
-        public override void Accept(IArrowTypeVisitor visitor)
-        {
-            if (visitor is IArrowTypeVisitor<UnionType> v)
-                v.Visit(this);
-        }
+        public override void Accept(IArrowTypeVisitor visitor) => Accept(this, 
visitor);
     }
 }
diff --git a/csharp/test/Apache.Arrow.Tests/Apache.Arrow.Tests.csproj 
b/csharp/test/Apache.Arrow.Tests/Apache.Arrow.Tests.csproj
index dca8e2d..d29279b 100644
--- a/csharp/test/Apache.Arrow.Tests/Apache.Arrow.Tests.csproj
+++ b/csharp/test/Apache.Arrow.Tests/Apache.Arrow.Tests.csproj
@@ -6,6 +6,7 @@
   <PropertyGroup>
     <TargetFramework>netcoreapp2.1</TargetFramework>
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+    <LangVersion>7.3</LangVersion>
   </PropertyGroup>
 
   <ItemGroup>
diff --git a/csharp/test/Apache.Arrow.Tests/ArrowBufferBuilderTests.cs 
b/csharp/test/Apache.Arrow.Tests/ArrowBufferBuilderTests.cs
new file mode 100644
index 0000000..eee4d14
--- /dev/null
+++ b/csharp/test/Apache.Arrow.Tests/ArrowBufferBuilderTests.cs
@@ -0,0 +1,176 @@
+// 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.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Xunit;
+
+namespace Apache.Arrow.Tests
+{
+    public class ArrowBufferBuilderTests
+    {
+        public class Append
+        {
+
+            [Fact]
+            public void DoesNotThrowWithNullParameters()
+            {
+                var builder = new ArrowBuffer.Builder<int>();
+
+                builder.AppendRange(null);
+                builder.Append((Func<IEnumerable<int>>) null);
+            }
+
+            [Fact]
+            public void CapacityOnlyGrowsWhenLengthWillExceedCapacity()
+            {
+                var builder = new ArrowBuffer.Builder<int>(1);
+                var capacity = builder.Capacity;
+
+                builder.Append(1);
+
+                Assert.Equal(capacity, builder.Capacity);
+            }
+
+            [Fact]
+            public void CapacityGrowsAfterAppendWhenLengthExceedsCapacity()
+            {
+                var builder = new ArrowBuffer.Builder<int>(1);
+                var capacity = builder.Capacity;
+
+                builder.Append(1);
+                builder.Append(2);
+
+                Assert.True(builder.Capacity > capacity);
+            }
+
+            [Fact]
+            public void CapacityGrowsAfterAppendSpan()
+            {
+                var builder = new ArrowBuffer.Builder<int>(1);
+                var capacity = builder.Capacity;
+                var data = Enumerable.Range(0, 10).Select(x => x).ToArray();
+
+                builder.Append(data);
+
+                Assert.True(builder.Capacity > capacity);
+            }
+
+            [Fact]
+            public void LengthIncrementsAfterAppend()
+            {
+                var builder = new ArrowBuffer.Builder<int>(1);
+                var length = builder.Length;
+
+                builder.Append(1);
+
+                Assert.Equal(length + 1, builder.Length);
+            }
+
+            [Fact]
+            public void LengthGrowsBySpanLength()
+            {
+                var builder = new ArrowBuffer.Builder<int>(1);
+                var data = Enumerable.Range(0, 10).Select(x => x).ToArray();
+
+                builder.Append(data);
+
+                Assert.Equal(10, builder.Length);
+            }
+
+            [Fact]
+            public void BufferHasExpectedValues()
+            {
+                var builder = new ArrowBuffer.Builder<int>(1);
+
+                builder.Append(10);
+                builder.Append(20);
+
+                var buffer = builder.Build();
+                var span = buffer.Span.CastTo<int>();
+
+                Assert.Equal(10, span[0]);
+                Assert.Equal(20, span[1]);
+                Assert.Equal(0, span[2]);
+            }
+        }
+
+        public class AppendRange
+        {
+            [Fact]
+            public void CapacityGrowsAfterAppendEnumerable()
+            {
+                var builder = new ArrowBuffer.Builder<int>(1);
+                var capacity = builder.Capacity;
+                var data = Enumerable.Range(0, 10).Select(x => x);
+
+                builder.AppendRange(data);
+
+                Assert.True(builder.Capacity > capacity);
+            }
+
+            [Fact]
+            public void LengthGrowsByEnumerableCount()
+            {
+                var builder = new ArrowBuffer.Builder<int>(1);
+                var length = builder.Length;
+                var data = Enumerable.Range(0, 10).Select(x => x).ToArray();
+                var count = data.Length;
+                
+                builder.AppendRange(data);
+
+                Assert.Equal(length + count, builder.Length);
+            }
+
+            [Fact]
+            public void BufferHasExpectedValues()
+            {
+                var builder = new ArrowBuffer.Builder<int>(1);
+                var data = Enumerable.Range(0, 10).Select(x => x).ToArray();
+
+                builder.AppendRange(data);
+
+                var buffer = builder.Build();
+                var span = buffer.Span.CastTo<int>();
+
+                for (var i = 0; i < 10; i++)
+                {
+                    Assert.Equal(i, span[i]);
+                }
+            }
+        }
+
+        public class Clear
+        {
+            [Fact]
+            public void SetsAllValuesToDefault()
+            {
+                var builder = new ArrowBuffer.Builder<int>(1);
+                var data = Enumerable.Range(0, 10).Select(x => x).ToArray();
+
+                builder.AppendRange(data);
+                builder.Clear();
+
+                var buffer = builder.Build();
+                var zeros = Enumerable.Range(0, 10).Select(x => 0).ToArray();
+                var values = buffer.Span.CastTo<int>().Slice(0, 10).ToArray();
+
+                Assert.True(zeros.SequenceEqual(values));
+            }
+        }
+
+    }
+}
diff --git a/csharp/test/Apache.Arrow.Tests/ArrowBufferTests.cs 
b/csharp/test/Apache.Arrow.Tests/ArrowBufferTests.cs
index 28de056..f618a9b 100644
--- a/csharp/test/Apache.Arrow.Tests/ArrowBufferTests.cs
+++ b/csharp/test/Apache.Arrow.Tests/ArrowBufferTests.cs
@@ -13,10 +13,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-using System;
-using System.Runtime.CompilerServices;
-using Apache.Arrow.Memory;
 using Apache.Arrow.Tests.Fixtures;
+using System;
 using Xunit;
 
 namespace Apache.Arrow.Tests
@@ -34,19 +32,20 @@ namespace Apache.Arrow.Tests
             }
 
             /// <summary>
-            /// Ensure Arrow buffers are allocated in multiples of 8-bytes.
+            /// Ensure Arrow buffers are allocated in multiples of 64 bytes.
             /// </summary>
             /// <param name="size">number of bytes to allocate</param>
             /// <param name="expectedCapacity">expected buffer capacity after 
allocation</param>
             [Theory]
-            [InlineData(1, 8)]
-            [InlineData(8, 8)]
-            [InlineData(9, 16)]
-            [InlineData(16, 16)]
+            [InlineData(1, 64)]
+            [InlineData(8, 64)]
+            [InlineData(9, 64)]
+            [InlineData(65, 128)]
             public void AllocatesWithExpectedPadding(int size, int 
expectedCapacity)
             {
-                var buffer = ArrowBuffer.Allocate(size, 
_memoryPoolFixture.MemoryPool);
-                Assert.Equal(buffer.Capacity, expectedCapacity);
+                var buffer = new ArrowBuffer.Builder<byte>(size).Build();
+
+                Assert.Equal(buffer.Length, expectedCapacity);
             }
 
             /// <summary>
@@ -59,12 +58,11 @@ namespace Apache.Arrow.Tests
             [InlineData(128)]
             public unsafe void AllocatesAlignedToMultipleOf64(int size)
             {
-                var buffer = ArrowBuffer.Allocate(size, 
_memoryPoolFixture.MemoryPool);
+                var buffer = new ArrowBuffer.Builder<byte>(size).Build();
 
-                using (var pin = buffer.Memory.Pin())
-                {
-                    var ptr = new IntPtr(pin.Pointer);
-                    Assert.True(ptr.ToInt64() % 64 == 0);
+                fixed (byte* ptr = &buffer.Span.GetPinnableReference())
+                { 
+                    Assert.True(new IntPtr(ptr).ToInt64() % 64 == 0);
                 }
             }
 
@@ -74,10 +72,9 @@ namespace Apache.Arrow.Tests
             [Fact]
             public void HasZeroPadding()
             {
-                var buffer = ArrowBuffer.Allocate(32, 
_memoryPoolFixture.MemoryPool);
-                var span = buffer.GetSpan<byte>();
-
-                foreach (var b in span)
+                var buffer = new ArrowBuffer.Builder<byte>(10).Build();
+                
+                foreach (var b in buffer.Span)
                 {
                     Assert.Equal(0, b);
                 }
diff --git 
a/csharp/test/Apache.Arrow.Tests/Fixtures/DefaultMemoryPoolFixture.cs 
b/csharp/test/Apache.Arrow.Tests/Fixtures/DefaultMemoryPoolFixture.cs
index a87bfae..3b867cd 100644
--- a/csharp/test/Apache.Arrow.Tests/Fixtures/DefaultMemoryPoolFixture.cs
+++ b/csharp/test/Apache.Arrow.Tests/Fixtures/DefaultMemoryPoolFixture.cs
@@ -23,10 +23,9 @@ namespace Apache.Arrow.Tests.Fixtures
 
         public DefaultMemoryPoolFixture()
         {
-            const int padding = 8;
             const int alignment = 64;
 
-            MemoryPool = new NativeMemoryPool(padding, alignment);
+            MemoryPool = new NativeMemoryPool(alignment);
         }
     }
 }

Reply via email to