【发布时间】:2018-06-14 04:14:07
【问题描述】:
在实际问题之前,一个小小的免责声明:
这是this one 的相关/后续问题,但因为这里我在谈论一个更普遍的问题(如何固定
ref T变量以便能够对其执行指针操作),我我提出了一个可能的(可能是错误的)解决方案,我提出了一个单独的问题。
所以,问题是:给定一个 ref T 变量(假设它是数组的第一项),我如何固定它,以便 GC 在处理底层数组时不会引起问题不安全的指针?
我不确定这在 C# 中是否可行(但我希望我错了),但是查看 IL 代码以找到一种仅修复 ref int 变量的方法,我试图想出一个变体致力于泛型类型。这是我的想法:
假设我在“MyTestClass”类中有这个delegate:
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 Standard 2.0 项目中的最佳方法是什么?
谢谢!
额外问题:我已经看到 CoreFX 存储库对具有 IL 类的项目使用“.ilproj”文件,但 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?
}
}
【问题讨论】:
-
我已经看到 CoreFX 存储库使用“.ilproj”文件来处理具有 IL 类的项目,但 VS 实际上并不支持它们。那是一些扩展还是他们使用自己的自定义脚本来支持该项目格式?如果你用谷歌搜索
ilproj,前三个链接会帮助你...... -
@ta.speot.is 是的,我这样做并看到了这些结果,但这些扩展似乎不是官方的(即不是来自 MS),第一个的描述说的是那些项目不能从 C# 项目中引用,您必须构建它们并链接 dll 本身。我希望有一个更简单的解决方案。
标签: c# .net visual-studio cil c#-7.2