Runtime: Introduce IDisposable in GCHandle

Created on 18 Jul 2018  路  5Comments  路  Source: dotnet/runtime

Since pointers are not allowed on generics, I have to do a lot of GCHandle.Alloc to pin my arrays so that I'm able to do mathematical operations on my arrays. See below an example. The problem is that I always have to use a try...finally construct to Free() the pinned handle again. So it would be nice fi the GCHandle implements and IDisposable so that I can encapsulate it into a using block.

```c#
private unsafe static void OffsetAndScale(Tout[] data_in, float scale_in, float offset_in) where Tout : unmanaged
{
if ((Math.Abs(scale_in - 1) > float.Epsilon) || (Math.Abs(offset_in) > float.Epsilon))
{
GCHandle aHandle = GCHandle.Alloc(data_in, GCHandleType.Pinned);
void* ptr = aHandle.AddrOfPinnedObject().ToPointer();

            int N = data_in.Length;

            try
            {
                switch (Type.GetTypeCode(typeof(Tout)))
                {
                    case TypeCode.Byte:
                        {
                            byte* p = (byte*)ptr;
                            for (int i = 0; i < N; i++, p++)
                                *p = (byte)((*p * scale_in) + offset_in);
                            break;
                        }

                    case TypeCode.Int16:
                        {
                            short* p = (short*)ptr;
                            for (int i = 0; i < N; i++, p++)
                                *p = (short)((*p * scale_in) + offset_in);
                            break;
                        }

                    case TypeCode.UInt16:
                        {
                            ushort* p = (ushort*)ptr;
                            for (int i = 0; i < N; i++, p++)
                                *p = (ushort)((*p * scale_in) + offset_in);
                            break;
                        }

                    case TypeCode.Int32:
                        {
                            int* p = (int*)ptr;
                            for (int i = 0; i < N; i++, p++)
                                *p = (int)((*p * scale_in) + offset_in);
                            break;
                        }

                    case TypeCode.UInt32:
                        {
                            uint* p = (uint*)ptr;
                            for (int i = 0; i < N; i++, p++)
                                *p = (uint)((*p * scale_in) + offset_in);
                            break;
                        }

                    case TypeCode.Int64:
                        {
                            long* p = (long*)ptr;
                            for (int i = 0; i < N; i++, p++)
                                *p = (long)((*p * scale_in) + offset_in);
                            break;
                        }

                    case TypeCode.UInt64:
                        {
                            ulong* p = (ulong*)ptr;
                            for (int i = 0; i < N; i++, p++)
                                *p = (ulong)((*p * scale_in) + offset_in);
                            break;
                        }

                    case TypeCode.Single:
                        {
                            float* p = (float*)ptr;
                            for (int i = 0; i < N; i++, p++)
                                *p = (float)((*p * scale_in) + offset_in);
                            break;
                        }

                    case TypeCode.Double:
                        {
                            double* p = (double*)ptr;
                            for (int i = 0; i < N; i++, p++)
                                *p = (double)((*p * scale_in) + offset_in);
                            break;
                        }
                }
            }
            finally
            {
                if (aHandle.IsAllocated)
                {
                    aHandle.Free();
                }
            }
        }
    }

```

api-suggestion area-System.Runtime

Most helpful comment

Nevertheless. Would it make sense to attach an IDisposable to the GCHandle as a long runner?

All 5 comments

Why wouldn't you just use fixed here instead of GCHandle, e.g.
C# fixed (Tout* ptr = data_in) { ... }

@stephentoub: Arghh. Thanks for pointing this out. Originally I used the constrained structand not unmanaged: I was changing this lately for this example and honestly I was not aware that I can use the pointers on unmanaged types now.

Nevertheless. Would it make sense to attach an IDisposable to the GCHandle as a long runner?

I've had this same impulse ever since I first started using GCHandle seven years ago.

This C# 8.0 candidate proposal would enable you to write your own Dispose() extension method for GCHandle to make it work in a using statement.

Thanks @jnm2 . I'm really waiting for the extension everything in C# 8. As you showed in the link it's a good thing. The only problem I have is with the proposal that the structural detection of let's say keywords I personally don't like that much, because it's not so obvious what happens under the hood.

An good example of structural detection that only a few people know is the StaticPropertyChanged what was introduced in .NET 4.5. Of course you have to read through the docs to finds things out, but I prefer some more obvious things.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

bencz picture bencz  路  3Comments

Timovzl picture Timovzl  路  3Comments

matty-hall picture matty-hall  路  3Comments

jzabroski picture jzabroski  路  3Comments

aggieben picture aggieben  路  3Comments