在实际问题之前,有一个小小的免责声明:
这是一个相关/后续问题
this one
,但从这里开始,我谈论的是一个更普遍的问题(如何固定
ref T
变量来执行指针操作),我提出了一个可能的(可能是错误的)解决方案,我提出了一个单独的问题。
所以,问题是:
给定
参考T
变量(假设它是数组的第一项),如何固定它,以便GC在使用不安全指针处理底层数组时不会造成问题?
我不确定这在C#中是否可行(但我希望我错了),但请查看IL代码中的一个方法,该方法只修复
ref int
变量,我试图想出一个可以处理泛型类型的变量。以下是我的想法:
假设我有这个
delegate
在类“MyTestClass”中:
public unsafe delegate void UnsafeAction(void* p);
然后,在IL中:
.method public hidebysig static void
Foo<valuetype .ctor (class [netstandard]System.ValueType) T>(
!!0/*T*/& r,
class MyTestClass/UnsafeAction action
) cil managed
{
.maxstack 2
.locals init (
[0] void* p,
[1] !!0/*T*/& pinned V_1
)
// Load the ref T argument into the pinned variable (as if fixed were used)
IL_0000: nop
IL_0001: ldarg.0 // r
IL_0002: stloc.1 // V_1
// Cast the T* pointer to void*
IL_0003: ldloc.1 // V_1
IL_0004: conv.u
IL_0005: stloc.0 // p
// Invoke the action passing the p pointer
IL_0006: ldarg.1 // action
IL_0007: ldloc.0 // p
IL_0008: callvirt instance void MyTestClass/UnsafeAction::Invoke(void*)
IL_000d: nop
// Set the pinned variable V_1 to NULL
IL_000e: ldc.i4.0
IL_000f: conv.u
IL_0010: stloc.1 // V_1
IL_0011: ret
}
我们的想法是能够像这样使用这种方法:
public static void Test<T>(this Span<T> span, Func<T> provider)
{
void Func(void* p)
{
// Do stuff with p, possibly in parallel
// eg. Unsafe.Write(p, provider());
}
Foo(ref span.DangerousGetPinnableReference(), Func);
}
你喜欢这个工作吗?如果是这样的话,将这样一个用IL编写的方法包含到现有方法中的最佳方法是什么。NET标准2.0项目?
谢谢
奖金问题
:我见过CoreFX repo使用“.ilproj”文件来支持具有IL类的项目,但VS实际上不支持这些文件。这是某种扩展,还是他们使用自己的自定义脚本来支持该项目格式?我知道有一个
ILProj extension
可用,但它既不是官方的,也与VS2017不兼容。
编辑
:我可能刚刚对如何解决此问题有了想法,请考虑以下事项:
public static void Foo<T>(ref T value)
{
fixed (void* p = &Unsafe.As<T, byte>(ref value))
{
// Shouldn't the ref T be correctly fixed here, since
// the "dummy" byte ref had the same address?
}
}