C ++ / CLI-Вопрос: есть ли в C # эквивалент ключевого слова «is» или мне нужно использовать отражение? - PullRequest
11 голосов
/ 03 апреля 2009

Я где-то читал в MSDN, что эквивалентом ключевого слова "#" в C # будет dynamic_cast, но это не совсем эквивалентно: оно не работает с типами значений или с общими параметрами. Например, в C # я могу написать:

void MyGenericFunction<T>()
{
    object x = ...
    if (x is T)
        ...;
}

Если я попробую «эквивалентный» C ++ / CLI:

generic<class T>
void MyGenericFunction()
{
    object x = ...
    if (dynamic_cast<T>(x))
       ...;
}

Я получаю ошибку компилятора "ошибка C2682: не могу использовать 'dynamic_cast' для преобразования из 'System :: Object ^' в 'T'".

Единственное, о чем я могу думать, это использовать отражение:

if (T::typeid->IsAssignableFrom(obj->GetType()))

Есть ли более простой способ сделать это?

Ответы [ 3 ]

13 голосов
/ 03 апреля 2009

Это на MSDN:

Как: реализовать и как ключевые слова C # в C ++

В двух словах вам нужно написать вспомогательную функцию, например:

template < class T, class U > 
Boolean isinst(U u) {
   return dynamic_cast< T >(u) != nullptr;
}

и назовите это так:

Object ^ o = "f";
if ( isinst< String ^ >(o) )
    Console::WriteLine("o is a string");
6 голосов
/ 03 апреля 2009

Вы можете использовать safe_cast там, где вы будете использовать dynamic_cast в нативном C ++ и перехватывать исключение System :: InvalidCastException. С точки зрения совместимых типов семантика запроса о том, можно ли преобразовать типы, может охватить более широкий диапазон типов, чем проверка идентичности. Возможно, вам действительно понадобится дополнительная гибкость IsAssignableFrom.

Я не думаю, что есть эффективный эквивалент старой доброй dynamic_cast идиомы, к которой мы привыкли, и, конечно, ничего более компактного.

1 голос
/ 24 ноября 2015

Хотя простой обходной путь заключается в использовании safe_cast<T>(x) и перехвате System::InvalidCastException^, это приводит к очевидным накладным расходам на обработку исключений (развертывание стека и все связанное с этим удовольствие), когда тип не соответствует.

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

#using <System.Core.dll>

namespace detail
{
    generic <typename T> ref class is_instance_of_managed_helper sealed abstract
    {
    public:
        static initonly System::Func<System::Object^, bool>^ is_instance_of = build();

    private:
        static System::Func<System::Object^, bool>^ build()
        {
            using System::Linq::Expressions::Expression;
            auto param = Expression::Parameter(System::Object::typeid);
            return Expression::Lambda<System::Func<System::Object^, bool>^>(
                Expression::TypeIs(param, T::typeid),
                param)->Compile();
        }
    };

    template <typename T> struct is_instance_of_helper
    {
        static bool is_instance_of(System::Object^ obj)
        {
            return is_instance_of_managed_helper<T>::is_instance_of(obj);
        }
    };

    template <typename T> struct is_instance_of_helper<T^>
    {
        static bool is_instance_of(System::Object^ obj)
        {
            return dynamic_cast<T^>(obj) != nullptr;
        }
    };
}

template <typename T> bool is_instance_of(System::Object^ obj)
{
    return detail::is_instance_of_helper<T>::is_instance_of(obj);
}

Немного объяснений:

  • is_instance_of_managed_helper - это управляемый класс, который генерирует функцию во время выполнения, давая эквивалент оператора C # is. Он использует Expression::TypeIs для достижения этого простым способом. Одна такая функция будет сгенерирована один раз для каждого T.

  • template <typename T> struct is_instance_of_helper - это шаблонная структура, которая просто использует вышеуказанное решение. Это общий случай.

  • template <typename T> struct is_instance_of_helper<T^> - это частичная специализация вышеуказанной структуры, которая использует dynamic_cast для типов управляемых дескрипторов. Таким образом, мы избавим себя от необходимости генерировать код во время выполнения, когда T можно просто использовать с dynamic_cast.

  • template <typename T> bool is_instance_of(System::Object^ obj) - последняя вспомогательная функция, которая выберет шаблон для использования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...