错误 CS1978:无法使用“uint*”类型的表达式作为动态分派操作的参数

发布于 2024-10-26 07:21:52 字数 663 浏览 2 评论 0 原文

我的代码如下所示:

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

I have code that looks like the following:

    public void GetData(dynamic dObj)
    {
        unsafe
        {
            byte[] myBuffer = new byte[255];
            uint myBufferCount = 0; 
            fixed (byte* myBufferPointer = myBuffer)
            {
                dObj.GetDatas(myBufferPointer, &myBufferCount);
            }
        }
    }

The idea is to call a function that will exist called "GetDatas", which takes a buffer and a count as pointers. However, this triggers the following error:

Error CS1978: Cannot use an expression of type 'uint*' as an argument to a dynamically dispatched operation

I can't find any further information on this error or how to resolve it. The MSDN docs seem unhelpful, as they do not seem to contain this error message at all. What is going wrong here? How do I dynamically call a function with the signature:

 void MyFunc(byte *buffer, uint *count);

?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

婴鹅 2024-11-02 07:21:53

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

根本原因是指​​针不能装箱。它们不能用作类型参数这一事实有点令人不安,因为我们完全可以将“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

The text from that error message is my own, and the story is that you cannot mix pointer-types and dynamic dispatch, period. Why?

The underlying reason is that pointers cannot be boxed. The fact that they cannot be used as type arguments is a bit of a red herring, since we are perfectly OK with "ref" types as dynamic arguments, and those can't be used as type arguments either. The compiler emits new delegate types to deal with ref types and it could probably do so to generate code in your assembly that creates a call site against a signature that has pointer-type parameters.

But back to the issue. Since pointers cannot be boxed, you can never have a pointer value in "dynamic," which means you can never really dynamically dispatch on a pointer. Also, since return values from dynamic calls are boxed, you cannot dynamically dispatch to a function that returns a pointer.

And so, in one respect you can think of this as one of those decisions that simplifies an issue for the user. It it a little complicated to say, ok, here are a few things you can do with pointers and dynamic, and there are some things you might be able to get away with for a while, so try to keep them straight. It's much easier to say (and remember) "no pointers with dynamic at all."

There is another issue, which I have to admit my memory is a little fuzzy on. Even if we did allow you to do this, the DLR would have to allow it. And when we were implementing C# 4.0, the DLR was a moving target, which meant the DLR and the C# runtime were really both moving targets. At various points, either one of those components were trying to box arguments for various reasons. I cannot recall what we shipped and whether that still happens, but anyway at least at some point in time this was a consideration.

It turns out "pointers occasionally with dynamic" is a feature that the various teams involved did not think was a very high priority. Which, of course, does not imply that we thought unsafe code in general is not high priority.

EDIT: I can't find any mention of this in the language specification. That is a spec bug. I'll make sure it gets reported.

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

把梦留给海 2024-11-02 07:21:53

正如我的评论中所指出的,我的猜测是问题的根源是 csharp 规范的第 25.1.1 节,并在后面进行了澄清

在不安全代码(§27)中,类型参数不应是指针类型

,因为 DLR 在内部有时会大量使用表达式树 Expression> 可能必须创建,但它不会工作。


我在这里重复我的评论只是为了能够发布一些代码,因为解决方案之一可能是使用 IntPtr。它有效,但你丢失了部分类型信息,所以我不知道它是否真的有用。

创建 IntPtr 结构可以避免失去类型安全性,可以允许使用动态,在这种情况下,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)
    {

    }
}

As specified in my comment my guess is that the base of the problem is section 25.1.1 of the csharp spec and clarified latter

In unsafe code (§27), a type-argument shall not be a pointer-type

as the DLR internally uses expression trees a lot at some point an Expression<Action<byte*, uint*>> might have to be created and it won't work.


I repeated my comment here just to be able to post some code, as one of the solution might be to use IntPtr. It works but you lose part of the type info so I don't know if it's really useful.

It avoid loosing type safety creating an IntPtr<T> struct may allow to use dynamics, in this case the T type would only be a marker for the DLR. But maybe it's overkill to do this just to be able to use the DLR with pointers.

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

    }
}
暮年慕年 2024-11-02 07:21:53

该错误消息强烈表明该方法根本行不通。您可能必须使用静态绑定(可能是声明 void GetDatas(byte *buffer, uint *count) 的接口)或手动反射。

The error message strongly suggests that approach simply isn't going to work. You may have to use either static binding (perhaps to an interface that declares void GetDatas(byte *buffer, uint *count)), or manual reflection.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文