Generic Struct като аргумент на c++/cli функция причинява грешка CS0570 във VS 2015, но не и във VS2013

Имаме решение, което се компилира перфектно във VS2013, но се проваля с грешка при компилация във VS2015.

Проблемът е стеснен до това:

Имаме c# проект A, който дефинира обща структура като тази:

public struct MyStruct<T>
{

    public MyStruct(T b)
    {
    }
}

Имаме c++/cli проект B, който дефинира функция като тази:

public ref class Class1
{

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

И накрая имам c# проект за команден ред 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 прави твърде лесно да се бърка в това и да се губят порции перф без никакво надникване от компилатора. Приложете простото правило, променливите от тип стойност не трябва никога да имат шапката. Променливите от референтен тип винаги трябва да имат шапката, освен ако не е предназначена семантика на стека (използване на оператор в C#).

person Hans Passant    schedule 14.08.2015
comment
Благодаря ви за обяснението, улеснява ме много в дискусиите с разработчиците. - person I_DRIVE_TOYOTA; 14.08.2015