Почему собственные возвращаемые типы генерируют исключение System.InvalidProgramException? - PullRequest
0 голосов
/ 13 февраля 2012

Почему это вызывает исключение InvalidProgramException?Различные варианты, которые я видел, говорили:

  1. JIT обнаружил внутреннее ограничение.

  2. Common Language Runtime обнаружил недопустимыйprogram.

Я упростил пример до минимального набора обстоятельств, которые я могу воспроизвести, чтобы воспроизвести проблему.Вы должны быть в состоянии получить приведенный ниже код и вставить его в VS2010, чтобы воспроизвести это.

Базовая структура, представленная ниже, состоит в том, что CppReferenceTest является сборкой CLR DLL, которая содержит метод, возвращающий нативную структуру.Рефери - консольное приложение CLR, пытающееся вызвать этот метод.Рефери имеет ссылку на проект CppReferenceTest.

Я знаю из другого тестирования, что вызов метода, внутреннего для CppReferenceTest, не вызовет исключение InvalidProgramException.Я также знаю, что если я изменю сигнатуру метода так, чтобы вместо контрольного значения вместо параметра возвращалось возвращаемое значение, исключение не выдается.

Сборка 1 - CppReferenceTest (библиотека DLL CLR)

Файл:NativeHeader.h

#pragma managed(push, off)

typedef struct _NativeStruct {
    int val1;
    int val2;
} NativeStruct;   

#pragma managed(pop)

Файл: CppReferenceTest.h

#pragma once

#include "NativeHeader.h"

using namespace System;

#pragma make_public(_NativeStruct)

namespace CppReferenceTest {

public ref class Class1
{
    public:
        static NativeStruct GetNativeEnum();
    };
}

Файл: CppReferenceTest.cpp

#include "stdafx.h"

#include "CppReferenceTest.h"

using namespace CppReferenceTest;

NativeStruct Class1::GetNativeEnum()
{
    NativeStruct ns = {1, 2};
    return ns;
}

Сборка 2 - Судья (консольное приложение CLR)

Файл: Referee.cpp

#include "stdafx.h"

#include "NativeHeader.h"

using namespace System;
using namespace CppReferenceTest;

int main(array<System::String ^> ^args)
{
    NativeStruct ns = Class1::GetNativeEnum();
    Console::WriteLine(L"Hello World");
    return 0;
}

1 Ответ

4 голосов
/ 13 февраля 2012

В .NET идентификатор типа включает сборку, из которой загружен тип. Поэтому НЕ следует использовать #include с управляемыми ссылками, только #import (вкладка "Ссылки" в настройках проекта эквивалентна #import).

То, что происходит сейчас, заключается в том, что #include -ing заголовочный файл, вы обещаете, что в текущей сборке есть тип _NativeStruct. Ваша функция main использует этот тип.

Затем во время выполнения CLR обнаруживает, что Class1::GetNativeEnum() возвращает другой тип _NativeStruct, определенный в CppReferenceTest.dll. Эти типы несовместимы, и вы получите исключение.

Просто используйте тип, указанный в метаданных сборки, на которую вы ссылаетесь.


В дополнение ко всему, не делайте typedef struct _NativeStruct NativeStruct в C ++. В этом нет необходимости, он запутывает сообщения об ошибках и, что еще хуже, конфликтует с зарезервированным идентификатором.

...