我在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()))
有更简单的方法吗?
答案 0 :(得分:13)
它在MSDN上:
How to: Implement is and as C# Keywords in 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");
答案 1 :(得分:6)
您可以使用safe_cast
在本地C ++中使用dynamic_cast
并捕获System :: InvalidCastException。就兼容类型而言,询问是否可以转换类型的语义可以选择比检查标识更广泛的类型。实际上,您可能希望增加IsAssignableFrom的灵活性。
我认为没有一个效率相当于我们习惯的好dynamic_cast
成语,当然没有任何紧凑。
答案 2 :(得分:1)
虽然一个简单的解决方法是使用safe_cast<T>(x)
并捕获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)
是最终帮助函数,它将选择要使用的模板。