虽然一个简单的解决方法是使用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)是选择要使用的模板的最终辅助函数。