错误CS1978:不能使用'uint *'类型的表达式作为动态调度操作的参数

时间:2011-03-24 11:31:42

标签: c# .net pointers dynamic unsafe

我的代码如下所示:

    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);

3 个答案:

答案 0 :(得分:4)

该错误消息中的文本是我自己的,故事是你不能混合指针类型和动态调度,句点。为什么呢?

根本原因是指​​针无法装箱。它们不能用作类型参数这一事实有点像红色鲱鱼,因为我们完全可以将“ref”类型作为动态参数,并且那些也不能用作类型参数。编译器发出新的委托类型来处理ref类型,它可能会在程序集中生成代码,该代码根据具有指针类型参数的签名创建调用站点。

但回到这个问题。由于指针不能被装箱,所以你永远不能在“动态”中有一个指针值,这意味着你永远不能真正动态地分配指针。此外,由于动态调用的返回值被加框,因此您无法动态调度到返回指针的函数。

因此,从某个方面来说,您可以将此视为简化用户问题的决策之一。说它有点复杂,好吧,这里有一些你可以用指针和动态做的事情,有些东西你可能能够侥幸逃脱一段时间,所以尽量保持它们。更容易说(并记住)“根本没有动态指针。”

还有另一个问题,我不得不承认我的记忆有点模糊。即使我们允许你这样做,DLR也必须允许它。当我们实现C#4.0时,DLR是一个移动目标,这意味着DLR和C#运行时实际上都是移动目标。在不同的点上,这些组件中的任何一个都试图出于各种原因打包参数。我不记得我们发货的是什么以及是否还会发生,但无论如何至少在某个时间点这是一个考虑因素。

事实证明,“偶尔有动态指针”是一个特征,参与的各个团队并不认为这是一个非常重要的优先事项。当然,这并不意味着我们认为不安全的代码通常不是高优先级。

编辑:我在语言规范中找不到任何提及。这是一个规范错误。我会确保报告。

编辑编辑:https://connect.microsoft.com/VisualStudio/feedback/details/653347/c-language-spec-ommission-cannot-mix-pointer-types-with-dynamic-dispatch

答案 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)的接口)或手动反射。