Ошибка: BindingFlags неоднозначен всякий раз, когда используется vcclr.h

Пытаясь немного поэкспериментировать с C++ CLI, ориентируясь на .NET 4.0 (не 4.5), я получаю немного раздражающую проблему. Код ниже дает предупреждение IntelliSense в моей Visual Studio 2012; он жалуется, что BindingFlags доступен в нескольких сборках. (Код компилируется нормально, но предупреждение раздражает, поскольку оно приводит к сбоям в работе IntelliSense.)

#include "stdafx.h"
#include <vcclr.h>

using namespace System;
using namespace System::Reflection;

int main(array<System::String ^> ^args)
{
    Console::WriteLine(L"Hello World");
    Console::ReadKey();

    auto properties = Console::typeid->GetProperties(BindingFlags::Instance | BindingFlags::Public);

    return 0;
}

Если я удаляю файл vcclr.h, все работает нормально. Я посмотрел файл, и там есть такая строка:

#using <mscorlib.dll>

Я предполагаю, что именно поэтому я получаю сообщение об ошибке. Мой проект уже автоматически ссылается на mscorlib.dll, и это использование заставляет Visual Studio попытаться загрузить его еще раз из другого места => конфликт.

Использование функции «Перейти к определению» (F12) в BindingFlags дает мне следующие пути:

enum class System::Reflection::BindingFlags - c:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\mscorlib.dll
enum class System::Reflection::BindingFlags - c:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.dll

Как мне обойти это? На данный момент я определенно не хочу ориентироваться на .NET 4.5, поскольку все пользователи в этом случае еще не используют .NET 4.5. Тем не менее, было бы «неплохо» заставить IntelliSens работать и в этом случае…


person Per Lundberg    schedule 08.05.2013    source источник
comment
Есть довольно серьезная проблема с директивой #using, она жестко запрограммирована сначала искать в каталоге .NET framework. Это было неприемлемо со времен .NET 4. Без сомнения, это очень сложно исправить так, чтобы не сломать многие старые проекты. Лучше всего поднять этот вопрос на сайте connect.microsoft.com. Не торопитесь, сохранив этот код в отдельном файле .cpp.   -  person Hans Passant    schedule 09.05.2013
comment
Спасибо за подсказку, Ганс, я тоже об этом потом подумал - сделать локальную копию файла vcclr.h с удаленной оскорбительной строкой... На основе этого ответ дам как можно скорее.   -  person Per Lundberg    schedule 09.05.2013


Ответы (1)


Как очень правильно заметил Ганс (спасибо!), текущий способ (без решения Microsoft основной проблемы) состоит в том, чтобы создать собственную локальную копию vcclr.h. Вот мой конечный результат. Теперь это отлично работает с IntelliSense, что приятно, потому что новое ключевое слово C++ "auto" (= var в C#) практически бесполезно без работы IntelliSense...

(Просматривая мою версию сейчас перед отправкой, вы, очевидно, также можете изменить определение _INC_VCCLR, чтобы оно не конфликтовало с версией Microsoft. Опять же, я чувствую, что в любом случае это должно быть более или менее заменой стандартного vcclr.h, поэтому это не проблема для меня.Кроме того, вы не хотели бы, чтобы материал был определен дважды, если какой-то файл случайно включает vcclr.h вместо этого, так что... может быть, лучше оставить его таким.)

//
//  vcclr_local.h - modified version of vcclr.h from c:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\vcclr.h.
//  Modifications indicated below.
//
//  Copyright (C) Microsoft Corporation
//  All rights reserved.
//

#if _MSC_VER > 1000
#pragma once
#endif

#if !defined(_INC_VCCLR)
#define _INC_VCCLR
#ifndef RC_INVOKED

// Deliberately disabled, since this causes mscorlib.dll to be references twice from two different locations, breaking
// IntelliSense whenever this header file is included.
//#using <mscorlib.dll>
#include <gcroot.h>

#pragma warning(push)
#pragma warning(disable:4400)

#ifdef __cplusplus_cli
typedef cli::interior_ptr<const System::Char> __const_Char_ptr;
typedef cli::interior_ptr<const System::Byte> __const_Byte_ptr;
typedef cli::interior_ptr<System::Byte> _Byte_ptr;
typedef const System::String^ __const_String_handle;
#define _NULLPTR nullptr
#else
typedef const System::Char* __const_Char_ptr;
typedef const System::Byte* __const_Byte_ptr;
typedef System::Byte* _Byte_ptr;
typedef const System::String* __const_String_handle;
#define _NULLPTR 0
#endif


//
// get an interior gc pointer to the first character contained in a System::String object
//
inline __const_Char_ptr PtrToStringChars(__const_String_handle s) {

    _Byte_ptr bp = const_cast<_Byte_ptr>(reinterpret_cast<__const_Byte_ptr>(s));
    if( bp != _NULLPTR ) {
    unsigned offset = System::Runtime::CompilerServices::RuntimeHelpers::OffsetToStringData;
        bp += offset;
    }
    return reinterpret_cast<__const_Char_ptr>(bp);
}

#pragma warning(pop)

#undef _NULLPTR

#endif /* RC_INVOKED */
#endif //_INC_VCCLR
person Per Lundberg    schedule 09.05.2013