I\'ve read somewhere on MSDN that the equivalent to C#\'s \"is\" keyword would be dynamic_cast, but that\'s not really equivalent: It doesn\'t work with value types or with
While a simple workaround would be to use safe_cast and catch System::InvalidCastException^, this has the obvious overhead of exception handling (unrolling the stack and all the related fun) when the type doesn't match.
I tried to come up with a different approach. While I wouldn't exactly call it simple, it does its job without using exceptions.
#using
namespace detail
{
generic ref class is_instance_of_managed_helper sealed abstract
{
public:
static initonly System::Func^ is_instance_of = build();
private:
static System::Func^ build()
{
using System::Linq::Expressions::Expression;
auto param = Expression::Parameter(System::Object::typeid);
return Expression::Lambda^>(
Expression::TypeIs(param, T::typeid),
param)->Compile();
}
};
template struct is_instance_of_helper
{
static bool is_instance_of(System::Object^ obj)
{
return is_instance_of_managed_helper::is_instance_of(obj);
}
};
template struct is_instance_of_helper
{
static bool is_instance_of(System::Object^ obj)
{
return dynamic_cast(obj) != nullptr;
}
};
}
template bool is_instance_of(System::Object^ obj)
{
return detail::is_instance_of_helper::is_instance_of(obj);
}
A bit of explanation:
is_instance_of_managed_helper is a managed class which generates a function at runtime giving the equivalent of C#'s is operator. It uses Expression::TypeIs to achieve this in a simple way. One such function will be generated once for every T.
template is a template struct which simply uses the above solution. This is the general case.
template is a partial specialization of the above struct which uses dynamic_cast for managed handle types. This way, we'll spare ourselves the trouble of generating code at runtime when T can simply be used with dynamic_cast.
template is the final helper function which will choose the template to use.