C++/CLI-Question: Is there an equivalent to the C# “is” keyword or do I have to use reflection?

后端 未结 3 1019
不知归路
不知归路 2021-01-01 23:38

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

相关标签:
3条回答
  • 2021-01-01 23:56

    While a simple workaround would be to use safe_cast<T>(x) 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 <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);
    }
    

    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 <typename T> struct is_instance_of_helper is a template struct which simply uses the above solution. This is the general case.

    • template <typename T> struct is_instance_of_helper<T^> 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 <typename T> bool is_instance_of(System::Object^ obj) is the final helper function which will choose the template to use.

    0 讨论(0)
  • 2021-01-02 00:12

    You can use safe_cast where you would use dynamic_cast in native C++ and trap the System::InvalidCastException. In terms of compatible types the semantics of asking if you can convert types could pick up a broader range of types than checking identity. You may actually want the added flexibility of IsAssignableFrom.

    I don't think there's an efficient equivalent to the good old dynamic_cast idiom we're used to, certainly nothing as compact.

    0 讨论(0)
  • 2021-01-02 00:13

    It's on MSDN:

    How to: Implement is and as C# Keywords in C++

    In a nutshell, you need to write a helper function like so:

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

    and call it like this:

    Object ^ o = "f";
    if ( isinst< String ^ >(o) )
        Console::WriteLine("o is a string");
    
    0 讨论(0)
提交回复
热议问题