代码之家  ›  专栏  ›  技术社区  ›  Niki

C++/CLI问题:有一个等价于C“是”关键字还是我必须使用反射?

  •  11
  • Niki  · 技术社区  · 17 年前

    我在msdn上的某个地方读到,等价于c s“i s”的关键字是动态的,但实际上并不等价:它不适用于值类型或通用参数。例如,在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”将“system::object^”转换为“t”。

    我唯一能想到的就是运用反思:

    if (T::typeid->IsAssignableFrom(obj->GetType()))
    

    有更简单的方法吗?

    3 回复  |  直到 10 年前
        1
  •  6
  •   Andy Dent    17 年前

    你可以使用 safe_cast 你将在哪里使用 dynamic_cast 在本机C++中并捕获St::ValueStudio异常。依据 兼容类型 询问是否可以转换类型的语义可以比检查标识获取更广泛的类型范围。实际上,您可能需要isassignablefrom的额外灵活性。

    我不认为有一个有效的等同于好的老 动态铸件 我们习惯了这个成语,当然没有比这更紧凑的了。

        2
  •  13
  •   Guido Domenici    17 年前

    它在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");
    
        3
  •  1
  •   Lucas Trzesniewski    10 年前

    而一个简单的解决方法就是 safe_cast<T>(x) 抓住 System::InvalidCastException^ 当类型不匹配时,这有明显的异常处理开销(展开堆栈和所有相关的乐趣)。

    我试图想出一个不同的方法。虽然我不会这么说 简单的 它不使用异常来完成它的工作。

    #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 可以简单地与 动态铸件 .

    • template <typename T> bool is_instance_of(System::Object^ obj) 是将选择要使用的模板的最终助手函数。

    推荐文章