我的代码如下所示:
public void GetData(dynamic dObj)
{
unsafe
{
byte[] myBuffer = new byte[255];
uint myBufferCount = 0;
fixed (byte* myBufferPointer = myBuffer)
{
dObj.GetDatas(myBufferPointer, &myBufferCount);
}
}
}
我们的想法是调用一个名为“GetDatas”的函数,该函数将缓冲区和计数作为指针。但是,这会触发以下错误:
错误CS1978:不能使用'uint *'类型的表达式作为动态调度操作的参数
我找不到有关此错误的更多信息或如何解决此错误。 MSDN文档似乎没有用,因为它们似乎根本不包含此错误消息。这里出了什么问题?如何使用签名动态调用函数:
void MyFunc(byte *buffer, uint *count);
答案 0 :(得分:4)
该错误消息中的文本是我自己的,故事是你不能混合指针类型和动态调度,句点。为什么呢?
根本原因是指针无法装箱。它们不能用作类型参数这一事实有点像红色鲱鱼,因为我们完全可以将“ref”类型作为动态参数,并且那些也不能用作类型参数。编译器发出新的委托类型来处理ref类型,它可能会在程序集中生成代码,该代码根据具有指针类型参数的签名创建调用站点。
但回到这个问题。由于指针不能被装箱,所以你永远不能在“动态”中有一个指针值,这意味着你永远不能真正动态地分配指针。此外,由于动态调用的返回值被加框,因此您无法动态调度到返回指针的函数。
因此,从某个方面来说,您可以将此视为简化用户问题的决策之一。说它有点复杂,好吧,这里有一些你可以用指针和动态做的事情,有些东西你可能能够侥幸逃脱一段时间,所以尽量保持它们。更容易说(并记住)“根本没有动态指针。”
还有另一个问题,我不得不承认我的记忆有点模糊。即使我们允许你这样做,DLR也必须允许它。当我们实现C#4.0时,DLR是一个移动目标,这意味着DLR和C#运行时实际上都是移动目标。在不同的点上,这些组件中的任何一个都试图出于各种原因打包参数。我不记得我们发货的是什么以及是否还会发生,但无论如何至少在某个时间点这是一个考虑因素。
事实证明,“偶尔有动态指针”是一个特征,参与的各个团队并不认为这是一个非常重要的优先事项。当然,这并不意味着我们认为不安全的代码通常不是高优先级。
编辑:我在语言规范中找不到任何提及。这是一个规范错误。我会确保报告。答案 1 :(得分:3)
正如我在评论中所指出的,我的猜测是问题的基础是csharp规范的第25.1.1节,并澄清了后者
在不安全的代码(第27节)中,类型参数不应是指针类型
由于DLR在某些时候内部使用了表达式树,因此可能必须创建Expression<Action<byte*, uint*>>
并且它不起作用。
我在这里重复我的评论只是为了能够发布一些代码,因为其中一个解决方案可能是使用IntPtr。它有效,但你丢失了部分类型信息,所以我不知道它是否真的有用。
避免失去类型安全性创建IntPtr<T>
结构可能允许使用动态,在这种情况下,T类型将只是DLR的标记。但是,为了能够使用带有指针的DLR,这样做可能太过分了。
void Main()
{
unsafe
{
var inst = new TestClass();
byte* test = stackalloc byte[5];
uint count;
inst.Test(test, &count);
}
unsafe
{
dynamic inst = new TestClass();
byte* test = stackalloc byte[5];
uint count;
inst.Test(new IntPtr(test), new IntPtr(&count));
}
}
class TestClass
{
public unsafe void Test(IntPtr buffer, IntPtr count)
{
Test((byte*)buffer.ToPointer(), (uint*)count.ToPointer());
}
public unsafe void Test(byte* buffer, uint* count)
{
}
}
答案 2 :(得分:1)
错误消息强烈暗示该方法根本不起作用。您可能必须使用静态绑定(可能是使用声明void GetDatas(byte *buffer, uint *count)
的接口)或手动反射。