Общая структура в качестве аргумента для функции c++/cli вызывает ошибку CS0570 в VS 2015, но не в VS2013

У нас есть решение, которое отлично компилируется в VS2013, но выдает ошибку компиляции в VS2015.

Проблема была сужена до этого:

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

public struct MyStruct<T>
{

    public MyStruct(T b)
    {
    }
}

У нас есть проект C++/cli B, который определяет такую ​​функцию:

public ref class Class1
{

public:
    void BadMethod(MyStruct<int> ^){};
};

И, наконец, у меня есть проект командной строки С# C, ссылающийся на проекты A и B и пытающийся вызвать BadMethod:

  class Program
    {
        static void Main(string[] args)
        {
            var c = new Class1();
            var s = new MyStruct<int>(0);

            c.BadMethod(s);
        }
    }

В Visual Studio 2013 (и старше) это компилируется без проблем, однако в Visual Studio 2015 мы получаем:

application\Program.cs(18,15,18,24): error CS0570: 'Class1.BadMethod(?)' is not supported by the language

Я попытался скомпилировать проект c++/cli с помощью набора инструментов Visual Studio 2015, но ошибка остается.

Использование универсального класса вместо структуры, кажется, работает.


person I_DRIVE_TOYOTA    schedule 14.08.2015    source источник
comment
Это похоже на github.com/dotnet/roslyn/issues/4163.   -  person svick    schedule 14.08.2015


Ответы (1)


   void BadMethod(MyStruct<int> ^){};

Удивительно, как часто новую версию VS обвиняют в программной ошибке. Тип MyStruct является типом значения. Но все же вы объявили тип аргумента как переменную ссылочного типа. Обратите внимание на шапку ^, которую вы использовали.

К сожалению, компилятор C++/CLI поддерживает это. Как и CLR, значение должно быть сначала упаковано, прежде чем его можно будет передать вызову метода. Очень неэффективно, цель использования типов значений всегда состоит в том, чтобы избежать упаковки. Однако в среде CLR нет аннотации типа для такого типа в штучной упаковке, он становится System::ValueType в метаданных. Во время выполнения проверьте, что значение имеет ожидаемый тип. Больше неэффективности, это добавляет к большим деньгам.

Язык C# вообще не поддерживает это и плюет на необходимость помещать значение в рамку. Без какой-либо возможности проверить, что это обязательный тип значения, он очень серьезно относится к проверке статического типа.

Исправление очень простое, просто опустите ^, чтобы аргумент передавался по значению и его не нужно было упаковывать. Если вы хотели передать значение по ссылке, что неясно из вопроса, то вместо этого вы должны использовать %.

И, вероятно, хорошая идея проверить остальную часть вашего кода, C++/CLI позволяет слишком легко возиться с этим и потерять кучу производительности без какого-либо взгляда со стороны компилятора. Примените простое правило: переменные типа значения не должны никогда иметь шляпу. Переменные ссылочного типа всегда должны иметь шляпу, если только не предназначена семантика стека (оператор using в C#).

person Hans Passant    schedule 14.08.2015
comment
Спасибо за объяснение, мне намного легче общаться с разработчиками. - person I_DRIVE_TOYOTA; 14.08.2015