Reputation: 518
I have a method which takes in a ref T*
and I need to reinterpret it as a ref nint
. Normally, I would use ref Unsafe.As<T*, nint>(ref value)
, but in this case that will not compile because "The type 'T*' may not be used as a type argument".
How can I reinterpret my ref T*
as a ref nint
?
Upvotes: 1
Views: 136
Reputation: 16574
This is a fun one.
First, I'm assuming you're already using unsafe
in your code since, well, pointers.
Try this:
static unsafe nint Exch<T>(ref T* ptr, nint val)
{
fixed (void* p = &ptr)
{
return Interlocked.Exchange(ref Unsafe.AsRef<nint>(p), val);
}
}
It's not as direct or efficient as @shingo's answer, but it seems to handle the exchange correctly.
This is what I tested with:
class Foo
{
public int Value { get; set; }
}
unsafe void Main()
{
Foo v1 = new() { Value = 12345 };
Foo* ptr = null;
Console.WriteLine($"Initial: {(nint)((void*)ptr):X}");
Console.WriteLine();
nint res1 = Exch(ref ptr, (nint)(&v1));
Console.WriteLine($"First: {res1:X} -> {(nint)((void*)ptr):X}");
Console.WriteLine();
nint res2 = Exch(ref ptr, 0);
Console.WriteLine($"Second: {res2:X} -> {(nint)((void*)ptr):X}");
}
Output:
Initial: 0
First: 0 -> 4920AFCE78
Second: 4920AFCE78 -> 0
Upvotes: 5
Reputation: 27164
I'm not sure how to achieve this using C#, but you can achieve this using IL: sharplab
.assembly UnsafeHelper {}
.module UnsafeHelper.dll
.class public auto ansi beforefieldinit UnsafeHelper
extends [System.Runtime]System.Object
{
.method public hidebysig static native int&
As<valuetype .ctor (class [System.Runtime]System.ValueType modreq([System.Runtime]System.Runtime.InteropServices.UnmanagedType)) T>(!!T*& p) cil managed
{
.param type T
.custom instance void [System.Runtime]System.Runtime.CompilerServices.IsUnmanagedAttribute::.ctor() = ( 01 00 00 00 )
.maxstack 8
IL_0000: ldarg.0
IL_0002: ret
}
}
Using ilasm
to compile this as a library, then you can use it:
double d = 2.75;
double* pd = &d;
ref var p2 = ref UnsafeHelper.As(ref pd);
Upvotes: 3