15

我在 MSDN 上的某处读到,与 C# 的“is”关键字等效的是 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()))

有没有更简单的方法来做到这一点?

4

3 回答 3

16

它在 MSDN 上:

如何:在 C++ 中实现 is 和 as 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");
于 2009-04-03T08:02:30.057 回答
7

您可以使用在本机 C++ 中使用的safe_cast位置dynamic_cast并捕获 System::InvalidCastException。就兼容类型而言,询问是否可以转换类型的语义可以选择比检查身份更广泛的类型。您实际上可能想要 IsAssignableFrom 增加的灵活性。

我不认为有一个有效的等价于dynamic_cast我们习惯的古老成语,当然没有什么比这更紧凑了。

于 2009-04-03T08:00:39.453 回答
1

虽然一个简单的解决方法是使用safe_cast<T>(x)和 catch System::InvalidCastException^,但当类型不匹配时,这会产生明显的异常处理开销(展开堆栈和所有相关的乐趣)。

我试图想出一种不同的方法。虽然我不会完全称它为simple,但它在不使用异常的情况下完成了它的工作。

#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)是选择要使用的模板的最终辅助函数。

于 2015-11-23T22:07:10.670 回答