C# 相当于C++的dynamic_cast是什么?

What's the C# equivalent to C++'s dynamic_cast?

本文关键字:cast 是什么 dynamic 相当于 C++      更新时间:2023-10-16

此C++代码检查o是否为Node *,如果是,则调用d上的方法。

if (Node * d = dynamic_cast<Node *>(o)) d->do_it();

用C#编写等效代码的最短和/或最有效的方法是什么?

假设Nodeclass,则执行以下

Node d = o as Node;
if (d != null) {
  d.do_it();
}

如果是struct,那么试试这个

if (o is Node) {
  ((Node)o).do_it();
}

从C#6开始(2015年7月),假设Nodeclass(或Nullable<T>string等),使用

  1. 检查o是否为Node(实际上与将o转换为Node不同——请参阅下面关于强制转换与转换的注意事项)
  2. 如果是,请致电do_it()
  3. 立即放弃强制值

您可以使用null条件运算符:

(o as Node)?.do_it();

此语法还处理o实际上被声明为Node,但恰好是null的情况。

如果你想保留强制转换变量,从C#7(2017年3月)开始,你可以运行:

if (o is Node node)
{
    node.do_it();
}

此时变量nodeif语句之外的范围内,相当于:

Node node = o as Node;
if (node != null) 
{
    node.do_it();
}

因此,如果你只想继续执行,如果oNode,你可以写:

if (!(o is Node node)) 
{
    return; // or continue, etc
}
node.do_it();
// ...

注意:如果onull,则is关键字将始终返回false,即使您直接指定类型,然后询问该变量是否为该类型。

string foo = null;
if (foo is string)
{
    // never gets here
    Console.WriteLine(foo);
}

铸造与转换

isas关键字的作用与C++的dynamic_cast<T>相同:它们将根据指定的类型、子类型或接口进行检查,但实际上不会更改内存中的值。它们只是告诉编译器应该在变量上使用哪些方法。

C#用户中有一个用词不当的地方,我们可以互换使用"cast"answers"convert"这两个词。这可能源于这样一个事实,即我们经常知道基类型变量总是一个子类型,因此当我们应该使用强制转换语法时,我们使用convert语法:

void Foo(MyBaseType value)
{
    // let's assume `value` will always be a MySubType
    MySubType subTypeValue = (MySubType)value;
}

如果value实际上不是MySubType,则此语法将在运行时抛出。

转换与强制转换的不同之处在于内存中的值可能会发生变化。考虑intdouble

void Foo()
{
    // implicit converting
    int x = 1;
    double y = x;
    // explicit converting
    y = 1.5;
    x = (int)y;
}

在每种情况下,存储在内存中的文字值都会更改格式。ints总是可以用double来表示——数据永远不会丢失——因此有一个定义的implicit operator,它将把内存中的数据处理成新的格式。doubles是浮点值,其范围大于ints,不能保证数据不丢失,因此C#需要通过explicit operator进行显式转换(通常称为"显式转换"),以向编译器表明我们可以处理数据丢失。

通过类,我们可以定义自己的隐式和显式运算符,这些运算符将以我们认为合适的方式操作数据。这就是convertcast之间用词不当的地方。

using System;
public class Program
{
    public static void Main()
    {
        Foo foo = new Foo();
        Bar bar = (Bar)foo;
        // writes "1" (or would, if the program compiled)
        Console.WriteLine(bar);
        // throws compilation error: "Cannot convert type `Foo' to `Bar' via built-in conversion"
        bar = foo as Bar;
        // note: the same would happen if `foo` was type int? and `bar` was type `double?`
        //       even though double? can be converted to int?
    }
}
class Foo
{
    public readonly int Value = 1;
    public static explicit operator Bar(Foo foo)
    {
        return new Bar(foo.Value.ToString());
    }
}
class Bar
{
    public readonly string Value;
    public Bar(string value)
    {
        Value = value;
    }
}

如果o不是Node:,则as运算符返回null

Node d = o as Node;
if (d != null)
{
    d.do_it();
}

您可以在C#中使用is关键字。

if (o is Node) 
{
}