Having the following two classes
interface IMask
{
string GetName();
}
readonly struct StructSource : IMask
{
string IMask.GetName()
{
throw new NotImplementedException();
}
}
How could we pass a reference to the ValueType
casted to the interface? So I don't have to propagate the generic argument down the line. Is it possible to achieve without heap allocating?
Suppose the following perfect world.
using System.Runtime.CompilerServices;
void UseValue<T>(ref T value) where T : IMask
{
ref IMask ptr = ref Unsafe.As<T, IMask>(ref value);
UseInterfaceReference(in ptr);
}
void UseInterfaceReference(in IMask target)
{
target.GetName();
}
but that does not work properly, the reference gets nullified possibly due to type inconsistency.
How could we pass a reference to the ValueType casted to the interface? So I don't have to propagate the generic argument down the line. Is it possible to achieve without heap allocating?
I think what you mean is:
Can I just use one generic method (UseValue<T>
) which is constrained to T:IMask
as entry point, so that I can make nonboxing IMask
interface calls in other nonconstrained nongeneric methods down the line?
The answer is NO.
You can see why really if you had two versions of UseValue
that just printed the result (without ref
for simplification)
void UseValueNonGeneric(IMask value){
var toPrint = value.GetName();
Console.WriteLine(toPrint);
}
void UseValue<T>(T value)
where T : IMask {
var toPrint = value.GetName();
Console.WriteLine(toPrint);
}
They do effectively the exact same thing, but differ in one thing - how the compiler emits the code for the actual interface call.
In the nongeneric case we have
callvirt instance string IMask::GetName()
in the generic case we have:
constrained. !!T
callvirt instance string IMask::GetName()
The second case is what you want to avoid boxing (allocation) as stated in the docs about the constrained
prefix:
When a
callvirt
method instruction has been prefixed byconstrained
thisType, the instruction is executed as follows:
- ...
- If thisType is a value type and thisType implements method then ptr is passed unmodified as the 'this' pointer to a call method
- ...
So, no matter if you were able to cast or not, you'd be unsuccessful because for the non-allocaiton (non-boxing) to even be able to happen you have to have a constrained generic method.
And this simply won't work:
void UseInterfaceReference(in IMask target)
{
target.GetName();
}