I've seen this code which was used showing the reference value :
static void Main(string[] args)
{
string s1 = "ab";
string s2 = "a"+"b";
string s3 = new StringBuilder("a").Append("b").ToString();
Console.WriteLine(GetMemoryAddress(s1));
Console.WriteLine(GetMemoryAddress(s2));
Console.WriteLine(GetMemoryAddress(s3));
}
static IntPtr GetMemoryAddress(object s1)
{
unsafe
{
TypedReference tr = __makeref(s1);
IntPtr ptr = **(IntPtr**) (&tr);
return ptr;
}
}
Result (as expected):
(I know that string interning kicks in here, but that's not the question).
Question:
Although it seems that it does do the job,
Does using __makeref
is this the right way of getting the reference value in c#?
Or are there any situations in which this ^ would fail ....?
Although it seems that it does do the job, Does using
__makeref
is this the right way of getting the reference value in c#?
There is no "right way" of doing this in C# - it isn't something you're meant to try and do, but: in terms of what it is doing - this is essentially relying on the internal layout of TypedReference
and a type coercion; it'll work (as long as TypedReference
doesn't change internally - for example the order of the Type
and Value
fields changes), but... it is nasty.
There is a more direct approach; in IL, you can convert from a managed pointer to an unmanaged pointer silently. Which means you can do something nasty like:
unsafe delegate void* RefToPointer(object obj);
static RefToPointer GetRef { get; } = MakeGetRef();
static RefToPointer MakeGetRef()
{
var dm = new DynamicMethod("evil", typeof(void*), new[] { typeof(object) });
var il = dm.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ret);
return (RefToPointer)dm.CreateDelegate(typeof(RefToPointer));
}
and now you can just do:
var ptr = new IntPtr(GetRef(o));
Console.WriteLine(ptr);
This is horrible, and you should never do it - and of course the GC can move things while you're not looking (or even while you are looking), but... it works.
Whether ref-emit is "better" than undocumented and unsupported language features like __makeref
and type-coercion: is a matter of some debate. Hopefully purely academic debate!