diff --git a/csharp/src/Apache.Arrow/C/CArrowArray.cs b/csharp/src/Apache.Arrow/C/CArrowArray.cs index a8a084d1d767d..fc609f10fdfa5 100644 --- a/csharp/src/Apache.Arrow/C/CArrowArray.cs +++ b/csharp/src/Apache.Arrow/C/CArrowArray.cs @@ -38,11 +38,11 @@ public unsafe struct CArrowArray public byte** buffers; public CArrowArray** children; public CArrowArray* dictionary; - internal delegate* unmanaged -#if !NET5_0_OR_GREATER - [Cdecl] +#if NET5_0_OR_GREATER + internal delegate* unmanaged release; +#else + internal IntPtr release; #endif - release; public void* private_data; /// @@ -68,10 +68,14 @@ internal delegate* unmanaged /// public static void Free(CArrowArray* array) { - if (array->release != null) + if (array->release != default) { // Call release if not already called. +#if NET5_0_OR_GREATER array->release(array); +#else + Marshal.GetDelegateForFunctionPointer(array->release)(array); +#endif } Marshal.FreeHGlobal((IntPtr)array); } diff --git a/csharp/src/Apache.Arrow/C/CArrowArrayExporter.cs b/csharp/src/Apache.Arrow/C/CArrowArrayExporter.cs index 5a793c177e0a6..16aaa3874b370 100644 --- a/csharp/src/Apache.Arrow/C/CArrowArrayExporter.cs +++ b/csharp/src/Apache.Arrow/C/CArrowArrayExporter.cs @@ -26,9 +26,9 @@ public static class CArrowArrayExporter #if NET5_0_OR_GREATER private static unsafe delegate* unmanaged ReleaseArrayPtr => &ReleaseArray; #else - private unsafe delegate void ReleaseArrowArray(CArrowArray* cArray); + internal unsafe delegate void ReleaseArrowArray(CArrowArray* cArray); private static unsafe readonly NativeDelegate s_releaseArray = new NativeDelegate(ReleaseArray); - private static unsafe delegate* unmanaged[Cdecl] ReleaseArrayPtr => (delegate* unmanaged[Cdecl])s_releaseArray.Pointer; + private static IntPtr ReleaseArrayPtr => s_releaseArray.Pointer; #endif /// /// Export an to a . Whether or not the @@ -93,7 +93,7 @@ public static unsafe void ExportRecordBatch(RecordBatch batch, CArrowArray* cArr { throw new ArgumentNullException(nameof(cArray)); } - if (cArray->release != null) + if (cArray->release != default) { throw new ArgumentException("Cannot export array to a struct that is already initialized.", nameof(cArray)); } @@ -191,7 +191,7 @@ private unsafe static void ConvertRecordBatch(ExportedAllocationOwner sharedOwne private unsafe static void ReleaseArray(CArrowArray* cArray) { Dispose(&cArray->private_data); - cArray->release = null; + cArray->release = default; } private unsafe static void* FromDisposable(IDisposable disposable) diff --git a/csharp/src/Apache.Arrow/C/CArrowArrayImporter.cs b/csharp/src/Apache.Arrow/C/CArrowArrayImporter.cs index e1314e5a62253..2f4ebed4b0cf1 100644 --- a/csharp/src/Apache.Arrow/C/CArrowArrayImporter.cs +++ b/csharp/src/Apache.Arrow/C/CArrowArrayImporter.cs @@ -17,6 +17,7 @@ using System; using System.Collections.Generic; +using System.Runtime.InteropServices; using Apache.Arrow.Memory; using Apache.Arrow.Types; @@ -104,21 +105,25 @@ public ImportedArrowArray(CArrowArray* cArray) { throw new ArgumentNullException(nameof(cArray)); } - if (cArray->release == null) + if (cArray->release == default) { throw new ArgumentException("Tried to import an array that has already been released.", nameof(cArray)); } _cArray = *cArray; - cArray->release = null; + cArray->release = default; } protected override void FinalRelease() { - if (_cArray.release != null) + if (_cArray.release != default) { fixed (CArrowArray* cArray = &_cArray) { +#if NET5_0_OR_GREATER cArray->release(cArray); +#else + Marshal.GetDelegateForFunctionPointer(cArray->release)(cArray); +#endif } } } diff --git a/csharp/src/Apache.Arrow/C/CArrowArrayStream.cs b/csharp/src/Apache.Arrow/C/CArrowArrayStream.cs index a900a6895a097..9cc9984c6ec8f 100644 --- a/csharp/src/Apache.Arrow/C/CArrowArrayStream.cs +++ b/csharp/src/Apache.Arrow/C/CArrowArrayStream.cs @@ -35,11 +35,11 @@ public unsafe struct CArrowArrayStream /// /// Return value: 0 if successful, an `errno`-compatible error code otherwise. /// - internal delegate* unmanaged -#if !NET5_0_OR_GREATER - [Cdecl] +#if NET5_0_OR_GREATER + internal delegate* unmanaged get_schema; +#else + internal IntPtr get_schema; #endif - get_schema; /// /// Callback to get the next array. If no error and the array is released, the stream has ended. @@ -47,11 +47,11 @@ internal delegate* unmanaged /// /// Return value: 0 if successful, an `errno`-compatible error code otherwise. /// - internal delegate* unmanaged -#if !NET5_0_OR_GREATER - [Cdecl] +#if NET5_0_OR_GREATER + internal delegate* unmanaged get_next; +#else + internal IntPtr get_next; #endif - get_next; /// /// Callback to get optional detailed error information. This must only @@ -62,21 +62,21 @@ internal delegate* unmanaged /// Return value: pointer to a null-terminated character array describing the last /// error, or NULL if no description is available. /// - internal delegate* unmanaged -#if !NET5_0_OR_GREATER - [Cdecl] +#if NET5_0_OR_GREATER + internal delegate* unmanaged get_last_error; +#else + internal IntPtr get_last_error; #endif - get_last_error; /// /// Release callback: release the stream's own resources. Note that arrays returned by /// get_next must be individually released. /// - internal delegate* unmanaged -#if !NET5_0_OR_GREATER - [Cdecl] +#if NET5_0_OR_GREATER + internal delegate* unmanaged release; +#else + internal IntPtr release; #endif - release; public void* private_data; @@ -103,10 +103,15 @@ internal delegate* unmanaged /// public static void Free(CArrowArrayStream* arrayStream) { - if (arrayStream->release != null) + if (arrayStream->release != default) { // Call release if not already called. +#if NET5_0_OR_GREATER + arrayStream->release(arrayStream); +#else + Marshal.GetDelegateForFunctionPointer(arrayStream->release)(arrayStream); +#endif } Marshal.FreeHGlobal((IntPtr)arrayStream); } diff --git a/csharp/src/Apache.Arrow/C/CArrowArrayStreamExporter.cs b/csharp/src/Apache.Arrow/C/CArrowArrayStreamExporter.cs index c748eed915d89..0a0f1cc837459 100644 --- a/csharp/src/Apache.Arrow/C/CArrowArrayStreamExporter.cs +++ b/csharp/src/Apache.Arrow/C/CArrowArrayStreamExporter.cs @@ -29,22 +29,18 @@ public static class CArrowArrayStreamExporter private static unsafe delegate* unmanaged GetLastErrorPtr => &GetLastError; private static unsafe delegate* unmanaged ReleasePtr => &Release; #else - private unsafe delegate int GetSchemaArrayStream(CArrowArrayStream* cArrayStream, CArrowSchema* cSchema); + internal unsafe delegate int GetSchemaArrayStream(CArrowArrayStream* cArrayStream, CArrowSchema* cSchema); private static unsafe NativeDelegate s_getSchemaArrayStream = new NativeDelegate(GetSchema); - private static unsafe delegate* unmanaged[Cdecl] GetSchemaPtr => - (delegate* unmanaged[Cdecl])s_getSchemaArrayStream.Pointer; - private unsafe delegate int GetNextArrayStream(CArrowArrayStream* cArrayStream, CArrowArray* cArray); + private static unsafe IntPtr GetSchemaPtr => s_getSchemaArrayStream.Pointer; + internal unsafe delegate int GetNextArrayStream(CArrowArrayStream* cArrayStream, CArrowArray* cArray); private static unsafe NativeDelegate s_getNextArrayStream = new NativeDelegate(GetNext); - private static unsafe delegate* unmanaged[Cdecl] GetNextPtr => - (delegate* unmanaged[Cdecl])s_getNextArrayStream.Pointer; - private unsafe delegate byte* GetLastErrorArrayStream(CArrowArrayStream* cArrayStream); + private static unsafe IntPtr GetNextPtr => s_getNextArrayStream.Pointer; + internal unsafe delegate byte* GetLastErrorArrayStream(CArrowArrayStream* cArrayStream); private static unsafe NativeDelegate s_getLastErrorArrayStream = new NativeDelegate(GetLastError); - private static unsafe delegate* unmanaged[Cdecl] GetLastErrorPtr => - (delegate* unmanaged[Cdecl])s_getLastErrorArrayStream.Pointer; - private unsafe delegate void ReleaseArrayStream(CArrowArrayStream* cArrayStream); + private static unsafe IntPtr GetLastErrorPtr => s_getLastErrorArrayStream.Pointer; + internal unsafe delegate void ReleaseArrayStream(CArrowArrayStream* cArrayStream); private static unsafe NativeDelegate s_releaseArrayStream = new NativeDelegate(Release); - private static unsafe delegate* unmanaged[Cdecl] ReleasePtr => - (delegate* unmanaged[Cdecl])s_releaseArrayStream.Pointer; + private static unsafe IntPtr ReleasePtr => s_releaseArrayStream.Pointer; #endif /// @@ -103,7 +99,7 @@ private unsafe static int GetNext(CArrowArrayStream* cArrayStream, CArrowArray* ExportedArrayStream arrayStream = null; try { - cArray->release = null; + cArray->release = default; arrayStream = ExportedArrayStream.FromPointer(cArrayStream->private_data); RecordBatch recordBatch = arrayStream.ArrowArrayStream.ReadNextRecordBatchAsync().Result; if (recordBatch != null) @@ -140,7 +136,7 @@ private unsafe static int GetNext(CArrowArrayStream* cArrayStream, CArrowArray* private unsafe static void Release(CArrowArrayStream* cArrayStream) { ExportedArrayStream.Free(&cArrayStream->private_data); - cArrayStream->release = null; + cArrayStream->release = default; } sealed unsafe class ExportedArrayStream : IDisposable diff --git a/csharp/src/Apache.Arrow/C/CArrowArrayStreamImporter.cs b/csharp/src/Apache.Arrow/C/CArrowArrayStreamImporter.cs index 7e70632bf82fc..fe0a307c9b26c 100644 --- a/csharp/src/Apache.Arrow/C/CArrowArrayStreamImporter.cs +++ b/csharp/src/Apache.Arrow/C/CArrowArrayStreamImporter.cs @@ -16,6 +16,7 @@ // under the License. using System; +using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Apache.Arrow.Ipc; @@ -57,7 +58,11 @@ private sealed unsafe class ImportedArrowArrayStream : IArrowArrayStream internal static string GetLastError(CArrowArrayStream* arrayStream, int errno) { +#if NET5_0_OR_GREATER byte* error = arrayStream->get_last_error(arrayStream); +#else + byte* error = Marshal.GetDelegateForFunctionPointer(arrayStream->get_last_error)(arrayStream); +#endif if (error == null) { return $"Array stream operation failed with no message. Error code: {errno}"; @@ -71,13 +76,17 @@ public ImportedArrowArrayStream(CArrowArrayStream* cArrayStream) { throw new ArgumentNullException(nameof(cArrayStream)); } - if (cArrayStream->release == null) + if (cArrayStream->release == default) { throw new ArgumentException("Tried to import an array stream that has already been released.", nameof(cArrayStream)); } CArrowSchema cSchema = new CArrowSchema(); +#if NET5_0_OR_GREATER int errno = cArrayStream->get_schema(cArrayStream, &cSchema); +#else + int errno = Marshal.GetDelegateForFunctionPointer(cArrayStream->get_schema)(cArrayStream, &cSchema); +#endif if (errno != 0) { throw new Exception(GetLastError(cArrayStream, errno)); @@ -85,7 +94,7 @@ public ImportedArrowArrayStream(CArrowArrayStream* cArrayStream) _schema = CArrowSchemaImporter.ImportSchema(&cSchema); _cArrayStream = *cArrayStream; - cArrayStream->release = null; + cArrayStream->release = default; } ~ImportedArrowArrayStream() @@ -111,12 +120,16 @@ public ValueTask ReadNextRecordBatchAsync(CancellationToken cancell CArrowArray cArray = new CArrowArray(); fixed (CArrowArrayStream* cArrayStream = &_cArrayStream) { +#if NET5_0_OR_GREATER int errno = cArrayStream->get_next(cArrayStream, &cArray); +#else + int errno = Marshal.GetDelegateForFunctionPointer(cArrayStream->get_next)(cArrayStream, &cArray); +#endif if (errno != 0) { return new(Task.FromException(new Exception(GetLastError(cArrayStream, errno)))); } - if (cArray.release != null) + if (cArray.release != default) { result = CArrowArrayImporter.ImportRecordBatch(&cArray, _schema); } @@ -127,12 +140,16 @@ public ValueTask ReadNextRecordBatchAsync(CancellationToken cancell public void Dispose() { - if (!_disposed && _cArrayStream.release != null) + if (!_disposed && _cArrayStream.release != default) { _disposed = true; fixed (CArrowArrayStream* cArrayStream = &_cArrayStream) { +#if NET5_0_OR_GREATER cArrayStream->release(cArrayStream); +#else + Marshal.GetDelegateForFunctionPointer(cArrayStream->release)(cArrayStream); +#endif } } GC.SuppressFinalize(this); diff --git a/csharp/src/Apache.Arrow/C/CArrowSchema.cs b/csharp/src/Apache.Arrow/C/CArrowSchema.cs index 64761dbd0d095..50c363b07720f 100644 --- a/csharp/src/Apache.Arrow/C/CArrowSchema.cs +++ b/csharp/src/Apache.Arrow/C/CArrowSchema.cs @@ -39,11 +39,11 @@ public unsafe struct CArrowSchema public long n_children; public CArrowSchema** children; public CArrowSchema* dictionary; - internal delegate* unmanaged -#if !NET5_0_OR_GREATER - [Cdecl] +#if NET5_0_OR_GREATER + internal delegate* unmanaged release; +#else + internal IntPtr release; #endif - release; public void* private_data; /// @@ -69,10 +69,14 @@ internal delegate* unmanaged /// public static void Free(CArrowSchema* schema) { - if (schema->release != null) + if (schema->release != default) { // Call release if not already called. +#if NET5_0_OR_GREATER schema->release(schema); +#else + Marshal.GetDelegateForFunctionPointer(schema->release)(schema); +#endif } Marshal.FreeHGlobal((IntPtr)schema); } diff --git a/csharp/src/Apache.Arrow/C/CArrowSchemaExporter.cs b/csharp/src/Apache.Arrow/C/CArrowSchemaExporter.cs index 9053e80664e31..696212eda36c7 100644 --- a/csharp/src/Apache.Arrow/C/CArrowSchemaExporter.cs +++ b/csharp/src/Apache.Arrow/C/CArrowSchemaExporter.cs @@ -30,9 +30,9 @@ public static class CArrowSchemaExporter #if NET5_0_OR_GREATER private static unsafe delegate* unmanaged ReleaseSchemaPtr => &ReleaseCArrowSchema; #else - private unsafe delegate void ReleaseArrowSchema(CArrowSchema* cArray); + internal unsafe delegate void ReleaseArrowSchema(CArrowSchema* cArray); private static unsafe readonly NativeDelegate s_releaseSchema = new NativeDelegate(ReleaseCArrowSchema); - private static unsafe delegate* unmanaged[Cdecl] ReleaseSchemaPtr => (delegate* unmanaged[Cdecl])s_releaseSchema.Pointer; + private static IntPtr ReleaseSchemaPtr => s_releaseSchema.Pointer; #endif /// @@ -297,7 +297,7 @@ private unsafe static void WriteMetadataString(ref byte* ptr, int length, string private static unsafe void ReleaseCArrowSchema(CArrowSchema* schema) { if (schema == null) return; - if (schema->release == null) return; + if (schema->release == default) return; Marshal.FreeHGlobal((IntPtr)schema->format); Marshal.FreeHGlobal((IntPtr)schema->name); @@ -324,7 +324,7 @@ private static unsafe void ReleaseCArrowSchema(CArrowSchema* schema) schema->n_children = 0; schema->dictionary = null; schema->children = null; - schema->release = null; + schema->release = default; } } } diff --git a/csharp/src/Apache.Arrow/C/CArrowSchemaImporter.cs b/csharp/src/Apache.Arrow/C/CArrowSchemaImporter.cs index 89c9481270c79..b21f24edba9af 100644 --- a/csharp/src/Apache.Arrow/C/CArrowSchemaImporter.cs +++ b/csharp/src/Apache.Arrow/C/CArrowSchemaImporter.cs @@ -113,7 +113,7 @@ public ImportedArrowSchema(CArrowSchema* cSchema) throw new ArgumentException("Passed null pointer for cSchema."); } _cSchema = cSchema; - if (_cSchema->release == null) + if (_cSchema->release == default) { throw new ArgumentException("Tried to import a schema that has already been released."); } @@ -128,9 +128,13 @@ public ImportedArrowSchema(CArrowSchema* handle, bool isRoot) : this(handle) public void Dispose() { // We only call release on a root-level schema, not child ones. - if (_isRoot && _cSchema->release != null) + if (_isRoot && _cSchema->release != default) { +#if NET5_0_OR_GREATER _cSchema->release(_cSchema); +#else + Marshal.GetDelegateForFunctionPointer(_cSchema->release)(_cSchema); +#endif } } diff --git a/csharp/test/Apache.Arrow.Tests/Apache.Arrow.Tests.csproj b/csharp/test/Apache.Arrow.Tests/Apache.Arrow.Tests.csproj index 55005a91c74a1..e7cfb95ad6ea1 100644 --- a/csharp/test/Apache.Arrow.Tests/Apache.Arrow.Tests.csproj +++ b/csharp/test/Apache.Arrow.Tests/Apache.Arrow.Tests.csproj @@ -3,6 +3,9 @@ net7.0 + true @@ -24,5 +27,9 @@ - - \ No newline at end of file + + + + + + diff --git a/csharp/test/Apache.Arrow.Tests/ArrayBuilderTests.cs b/csharp/test/Apache.Arrow.Tests/ArrayBuilderTests.cs index 0c40fd82af7ce..2568e5e8bdab8 100644 --- a/csharp/test/Apache.Arrow.Tests/ArrayBuilderTests.cs +++ b/csharp/test/Apache.Arrow.Tests/ArrayBuilderTests.cs @@ -26,6 +26,7 @@ public class ArrayBuilderTests { // TODO: Test various builder invariants (Append, AppendRange, Clear, Resize, Reserve, etc) +#if NET5_0_OR_GREATER [Fact] public void PrimitiveArrayBuildersProduceExpectedArray() { @@ -73,6 +74,7 @@ static void Test() where TBuilder : PrimitiveArrayBuilder, new() => TestArrayBuilder(x => x.Append(T.CreateChecked(123)).AppendNull().AppendNull().Append(T.CreateChecked(127)), 4, 2, 0x09); } +#endif [Fact] public void BooleanArrayBuilderProducersExpectedArray() diff --git a/csharp/test/Apache.Arrow.Tests/ArrowArrayTests.cs b/csharp/test/Apache.Arrow.Tests/ArrowArrayTests.cs index 16fca684ff5ec..d4f0d8dfd0383 100644 --- a/csharp/test/Apache.Arrow.Tests/ArrowArrayTests.cs +++ b/csharp/test/Apache.Arrow.Tests/ArrowArrayTests.cs @@ -93,6 +93,7 @@ void TestIsValid(ArrowBuffer valueBuf, ArrowBuffer nullBitmapBuf, int length, in } } +#if NET5_0_OR_GREATER [Fact] public void SliceArray() { @@ -145,6 +146,7 @@ static void TestNumberSlice() where TBuilder : PrimitiveArrayBuilder, new() => TestSlice(x => x.AppendNull().Append(T.CreateChecked(10)).Append(T.CreateChecked(20)).AppendNull().Append(T.CreateChecked(30))); } +#endif [Fact] public void SliceBooleanArray() @@ -198,7 +200,9 @@ private class ArraySliceValidator : IArrowArrayVisitor, IArrowArrayVisitor, IArrowArrayVisitor, +#if NET5_0_OR_GREATER IArrowArrayVisitor, +#endif IArrowArrayVisitor, IArrowArrayVisitor, IArrowArrayVisitor, @@ -240,7 +244,9 @@ public void Visit(Date64Array array) public void Visit(Time32Array array) => ValidateArrays(array); public void Visit(Time64Array array) => ValidateArrays(array); +#if NET5_0_OR_GREATER public void Visit(HalfFloatArray array) => ValidateArrays(array); +#endif public void Visit(FloatArray array) => ValidateArrays(array); public void Visit(DoubleArray array) => ValidateArrays(array); public void Visit(StringArray array) => ValidateArrays(array); diff --git a/csharp/test/Apache.Arrow.Tests/ArrowReaderVerifier.cs b/csharp/test/Apache.Arrow.Tests/ArrowReaderVerifier.cs index acfe72f83195e..543b446bba876 100644 --- a/csharp/test/Apache.Arrow.Tests/ArrowReaderVerifier.cs +++ b/csharp/test/Apache.Arrow.Tests/ArrowReaderVerifier.cs @@ -74,7 +74,9 @@ private class ArrayComparer : IArrowArrayVisitor, IArrowArrayVisitor, IArrowArrayVisitor, +#if NET5_0_OR_GREATER IArrowArrayVisitor, +#endif IArrowArrayVisitor, IArrowArrayVisitor, IArrowArrayVisitor, @@ -112,7 +114,9 @@ public ArrayComparer(IArrowArray expectedArray, bool strictCompare) public void Visit(UInt16Array array) => CompareArrays(array); public void Visit(UInt32Array array) => CompareArrays(array); public void Visit(UInt64Array array) => CompareArrays(array); +#if NET5_0_OR_GREATER public void Visit(HalfFloatArray array) => CompareArrays(array); +#endif public void Visit(FloatArray array) => CompareArrays(array); public void Visit(DoubleArray array) => CompareArrays(array); public void Visit(BooleanArray array) => CompareArrays(array); diff --git a/csharp/test/Apache.Arrow.Tests/ArrowStreamReaderTests.cs b/csharp/test/Apache.Arrow.Tests/ArrowStreamReaderTests.cs index 0e8c9d6687a02..ed030cc6ace11 100644 --- a/csharp/test/Apache.Arrow.Tests/ArrowStreamReaderTests.cs +++ b/csharp/test/Apache.Arrow.Tests/ArrowStreamReaderTests.cs @@ -224,6 +224,7 @@ private class PartialReadStream : MemoryStream // by default return 20 bytes at a time public int PartialReadLength { get; set; } = 20; +#if NET5_0_OR_GREATER public override int Read(Span destination) { if (destination.Length > PartialReadLength) @@ -243,6 +244,17 @@ public override ValueTask ReadAsync(Memory destination, CancellationT return base.ReadAsync(destination, cancellationToken); } +#else + public override int Read(byte[] buffer, int offset, int length) + { + return base.Read(buffer, offset, Math.Min(length, PartialReadLength)); + } + + public override Task ReadAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken = default) + { + return base.ReadAsync(buffer, offset, Math.Min(length, PartialReadLength), cancellationToken); + } +#endif } } } diff --git a/csharp/test/Apache.Arrow.Tests/CDataInterfaceDataTests.cs b/csharp/test/Apache.Arrow.Tests/CDataInterfaceDataTests.cs index a430e140cfc2a..2bd4d4d661942 100644 --- a/csharp/test/Apache.Arrow.Tests/CDataInterfaceDataTests.cs +++ b/csharp/test/Apache.Arrow.Tests/CDataInterfaceDataTests.cs @@ -47,7 +47,7 @@ public unsafe void InitializeArrayZeroed() Assert.True(cArray->buffers == null); Assert.True(cArray->children == null); Assert.True(cArray->dictionary == null); - Assert.True(cArray->release == null); + Assert.True(cArray->release == default); Assert.True(cArray->private_data == null); CArrowArray.Free(cArray); @@ -59,12 +59,13 @@ public unsafe void CallsReleaseForValid() IArrowArray array = GetTestArray(); CArrowArray* cArray = CArrowArray.Create(); CArrowArrayExporter.ExportArray(array, cArray); - Assert.False(cArray->release == null); + Assert.False(cArray->release == default); CArrowArrayImporter.ImportArray(cArray, array.Data.DataType).Dispose(); - Assert.True(cArray->release == null); + Assert.True(cArray->release == default); CArrowArray.Free(cArray); } +#if NET5_0_OR_GREATER [Fact] public unsafe void CallsReleaseForInvalid() { @@ -75,7 +76,7 @@ public unsafe void CallsReleaseForInvalid() var releaseCallback = (CArrowArray* cArray) => { wasCalled = true; - cArray->release = null; + cArray->release = default; }; cArray->release = (delegate* unmanaged)Marshal.GetFunctionPointerForDelegate( releaseCallback); @@ -90,5 +91,6 @@ public unsafe void CallsReleaseForInvalid() GC.KeepAlive(releaseCallback); } +#endif } } diff --git a/csharp/test/Apache.Arrow.Tests/CDataInterfacePythonTests.cs b/csharp/test/Apache.Arrow.Tests/CDataInterfacePythonTests.cs index 084d7bfb014cc..0923978225b5b 100644 --- a/csharp/test/Apache.Arrow.Tests/CDataInterfacePythonTests.cs +++ b/csharp/test/Apache.Arrow.Tests/CDataInterfacePythonTests.cs @@ -49,7 +49,7 @@ public CDataSchemaPythonTest() PythonEngine.Initialize(); if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && - !PythonEngine.PythonPath.Contains("dlls", StringComparison.OrdinalIgnoreCase)) + PythonEngine.PythonPath.IndexOf("dlls", StringComparison.OrdinalIgnoreCase) < 0) { dynamic sys = Py.Import("sys"); sys.path.append(Path.Combine(Path.GetDirectoryName(Environment.GetEnvironmentVariable("PYTHONNET_PYDLL")), "DLLs")); @@ -360,7 +360,7 @@ public unsafe void ExportType() } // Python should have called release once `exportedPyType` went out-of-scope. - Assert.True(cSchema->release == null); + Assert.True(cSchema->release == default); Assert.True(cSchema->format == null); Assert.Equal(0, cSchema->flags); Assert.Equal(0, cSchema->n_children); @@ -395,7 +395,7 @@ public unsafe void ExportField() // Python should have called release once `exportedPyField` went out-of-scope. Assert.True(cSchema->name == null); - Assert.True(cSchema->release == null); + Assert.True(cSchema->release == default); Assert.True(cSchema->format == null); // Since we allocated, we are responsible for freeing the pointer. diff --git a/csharp/test/Apache.Arrow.Tests/CDataInterfaceSchemaTests.cs b/csharp/test/Apache.Arrow.Tests/CDataInterfaceSchemaTests.cs index dfd6f9912cd4d..4aa5eb6b4d7ed 100644 --- a/csharp/test/Apache.Arrow.Tests/CDataInterfaceSchemaTests.cs +++ b/csharp/test/Apache.Arrow.Tests/CDataInterfaceSchemaTests.cs @@ -35,7 +35,7 @@ public unsafe void InitializeZeroed() Assert.Equal(0, cSchema->n_children); Assert.True(cSchema->children == null); Assert.True(cSchema->dictionary == null); - Assert.True(cSchema->release == null); + Assert.True(cSchema->release == default); Assert.True(cSchema->private_data == null); CArrowSchema.Free(cSchema); @@ -86,12 +86,13 @@ public unsafe void CallsReleaseForValid() { CArrowSchema* cSchema = CArrowSchema.Create(); CArrowSchemaExporter.ExportType(Int32Type.Default, cSchema); - Assert.False(cSchema->release == null); + Assert.False(cSchema->release == default); CArrowSchemaImporter.ImportType(cSchema); - Assert.True(cSchema->release == null); + Assert.True(cSchema->release == default); CArrowSchema.Free(cSchema); } +#if NET5_0_OR_GREATER // can't round-trip marshaled delegate [Fact] public unsafe void CallsReleaseForInvalid() { @@ -103,7 +104,7 @@ public unsafe void CallsReleaseForInvalid() var releaseCallback = (CArrowSchema* cSchema) => { wasCalled = true; - cSchema->release = null; + cSchema->release = default; }; cSchema->release = (delegate* unmanaged)Marshal.GetFunctionPointerForDelegate( releaseCallback); @@ -117,5 +118,6 @@ public unsafe void CallsReleaseForInvalid() GC.KeepAlive(releaseCallback); } +#endif } } diff --git a/csharp/test/Apache.Arrow.Tests/Extensions/Net472Extensions.cs b/csharp/test/Apache.Arrow.Tests/Extensions/Net472Extensions.cs new file mode 100644 index 0000000000000..0b298dec414c0 --- /dev/null +++ b/csharp/test/Apache.Arrow.Tests/Extensions/Net472Extensions.cs @@ -0,0 +1,34 @@ +// 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.Collections.Generic; + +namespace Apache.Arrow.Tests +{ + internal static class Net472Extensions + { + public static IEnumerable<(TFirst First, TSecond Second)> Zip(this IEnumerable first, IEnumerable second) + { + using (var enumerator1 = first.GetEnumerator()) + using (var enumerator2 = second.GetEnumerator()) + { + while (enumerator1.MoveNext() && enumerator2.MoveNext()) + { + yield return (enumerator1.Current, enumerator2.Current); + } + } + } + } +}