C++/CLI-问题:是否有与 C# 的“is”等价的命令? 关键字还是我必须使用反射?

发布于 2024-07-16 06:19:14 字数 582 浏览 4 评论 0原文

我在 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()))

有没有更简单的方法来做到这一点?

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 generic parameters. For example in C# I can write:

void MyGenericFunction<T>()
{
    object x = ...
    if (x is T)
        ...;
}

If I try the "equivalent" C++/CLI:

generic<class T>
void MyGenericFunction()
{
    object x = ...
    if (dynamic_cast<T>(x))
       ...;
}

I get a compiler error "error C2682: cannot use 'dynamic_cast' to convert from 'System::Object ^' to 'T'".

The only thing I can think of is to use reflection:

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

Is there a simpler way to do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

爱你是孤单的心事 2024-07-23 06:19:14

它位于 MSDN 上:

如何:在 C++ 中实现 is 和 as 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");

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");
熊抱啵儿 2024-07-23 06:19:14

您可以在本机 C++ 中使用 dynamic_cast 的地方使用 safe_cast 并捕获 System::InvalidCastException。 就兼容类型而言,询问是否可以转换类型的语义可以选择比检查身份更广泛的类型。 您可能实际上想要 IsAssignableFrom 增加的灵活性。

我认为没有一个有效的方法可以与我们习惯的旧的 dynamic_cast 习惯用法等效,当然也没有比它更紧凑的方法。

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.

冧九 2024-07-23 06:19:14

虽然一个简单的解决方法是使用 safe_cast(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_driven_helper 是一个托管类,它在运行时生成一个函数,相当于 C# 的 is 运算符。 它使用 Expression::TypeIs以简单的方式实现这一点。 对于每个 T 都会生成一个这样的函数一次

  • 模板 <类型名称 T> struct is_instance_of_helper 是一个模板结构,它仅使用上述解决方案。 这是一般情况。

  • 模板 <类型名称 T> struct is_instance_of_helper 是上述结构的部分特化,它使用 dynamic_cast 来表示托管句柄类型。 这样,当 T 可以简单地与 dynamic_cast 一起使用时,我们就可以省去在运行时生成代码的麻烦。

  • 模板 <类型名称 T> bool is_instance_of(System::Object^ obj) 是最终的辅助函数,它将选择要使用的模板。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文