【问题标题】:Declare the nativeptr<unit> type声明 nativeptr<unit> 类型
【发布时间】:2010-12-28 19:40:03
【问题描述】:

我想知道是否可以在 F# 中声明类型:

nativeptr<unit>

这似乎是不可能的(编译器抱怨 “泛型构造要求类型 'unit' 是非托管类型”)。有没有我可以使用的解决方法?

最终目标是声明我自己的 blitDelegate,以便将操作码 Cpblk 暴露给我的一些 F# 代码。

谢谢。

编辑:

这是我根据 kvb 的回答尝试过的:

type blitDelegate<'T when 'T : unmanaged> = delegate of nativeptr<'T> * nativeptr<'T> * uint32 -> unit

let createBlitDelegate<'T when 'T : unmanaged>() =
    let dm = new DynamicMethod("blit",
                               typeof<System.Void>,
                               [| typeof<nativeptr<'T>>; typeof<nativeptr<'T>>; typeof<uint32> |])
    let ilGenerator = dm.GetILGenerator()
    ilGenerator.Emit(OpCodes.Ldarg_0)
    ilGenerator.Emit(OpCodes.Ldarg_1)
    ilGenerator.Emit(OpCodes.Ldarg_2)
    ilGenerator.Emit(OpCodes.Cpblk)
    ilGenerator.Emit(OpCodes.Ret)
    dm.CreateDelegate(typeof<blitDelegate<'T>>) :?> blitDelegate<'T>

let blit (blitDel:blitDelegate<'T>) dst src byteWidth = blitDel.Invoke(dst, src, byteWidth)

然后我像这样从类成员中调用此代码:

let dst = //get nativeint destination address
let src = //get nativeint source address

let bd = createBlitDelegate<'T>()

let tdst = NativePtr.ofNativeInt<'T> dst
let tsrc = NativePtr.ofNativeInt<'T> src

do blit bd tdst tsrc (uint32 size)
//Program.MemCpy.Invoke(dst.ToPointer(), dst.ToPointer(), uint32 size)

这会导致 blit 出现运行时错误(System.Security.VerificationException:操作可能会破坏运行时。

注释代码运行良好(可以在 here 找到),但我的意思是用 F#(不是 C#)对其进行编码。

我一开始想使用nativeptr&lt;unit&gt;的原因是它实际上是MemCpy委托的两个第一个参数的类型(匹配void*类型)并且有点想模仿它。

编辑2:

基于 kvb 的编辑,我修改了代码以使用静态成员(如 C# 版本)在类型中托管委托创建,现在它可以工作了。 我不使用具有非托管约束的版本,而是使用这个版本,因为我实际上需要 blit 结构数组:

type blitDelegate = delegate of nativeint * nativeint * uint32 -> unit

【问题讨论】:

    标签: f# interop native c#-to-f# unit-type


    【解决方案1】:

    根据您的描述,我不清楚您为什么想要nativeptr&lt;unit&gt;。从本质上讲,nativeptr&lt;'t&gt; 只是nativeint 的一个薄包装器,带有一些用于对指针进行算术运算的助手。由于您不太可能拥有units 数组,但我看不出这实际上对您有什么帮助。也许如果您显示更多代码,则更容易给出更令人满意的答案。

    编辑

    我认为你做的几乎所有事情都是正确的。但是,匿名托管的DynamicMethods 必须是可验证的,而cpblk 操作码永远是不可验证的。尝试为 DynamicMethod 使用不同的构造函数将其托管在类型或模块上。

    【讨论】:

    • 是的,这确实是问题所在。非常感谢。
    • 另一个提示:如果您希望 IL cpblk 指令在使用托管指针时支持标准 .NET 数组 协方差(例如) TDerived[] 数组 sourceTBase[] destination,那么您必须通过放置 @ 来创建具有所谓“受控可变性”的源 ref OpCodes.Ldelema 指令之前的 987654332@ 前缀。否则,如果源数组的实际类型具有派生元素类型,您将崩溃并出现 ArrayTypeMismatchException 异常 "Attempted to access an element as a type in compatible with the array" .
    • ... 用于(例如)将一个 !T 元素从 srcArr[ix] 协变复制到 !T&amp; pDst 的 IL 最终看起来像这样:ldarg pDst; ldarg srcArr; ldarg ix; readonly. ldelema !T; sizeof !T; cpblk
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-25
    • 2022-08-12
    • 1970-01-01
    • 2020-05-12
    相关资源
    最近更新 更多