Ошибка CS1978: невозможно использовать выражение типа 'uint *' в качестве аргумента для динамически отправляемой операции. - PullRequest
2 голосов
/ 24 марта 2011

У меня есть код, который выглядит следующим образом:

    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 ]

4 голосов
/ 24 марта 2011

Текст из этого сообщения об ошибке мой, и история в том, что вы не можете смешивать типы указателей и динамическую отправку, точку.Почему?

Основная причина в том, что указатели не могут быть упакованы.Тот факт, что они не могут быть использованы в качестве аргументов типа, является чем-то вроде красной сельди, поскольку у нас все в порядке с типами «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

3 голосов
/ 24 марта 2011

Как указано в моем комментарии, я предполагаю, что в основе проблемы лежит раздел 25.1.1 спецификации csharp и уточнено последнее

В небезопасном коде (§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)
    {

    }
}
1 голос
/ 24 марта 2011

Сообщение об ошибке настоятельно предполагает, что подход просто не будет работать. Возможно, вам придется использовать либо статическую привязку (возможно, к интерфейсу, который объявляет void GetDatas(byte *buffer, uint *count)), либо ручное отражение.

...