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

Mar*_*ith 11 c# c++ casting

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

if (Node * d = dynamic_cast<Node *>(o)) d->do_it();
Run Code Online (Sandbox Code Playgroud)

在C#中编写等效的最短和/或最有效的方法是什么?

Jar*_*Par 21

假设那Node是一个class然后做以下

Node d = o as Node;
if (d != null) {
  d.do_it();
}
Run Code Online (Sandbox Code Playgroud)

如果相反它是一个struct然后试试这个

if (o is Node) {
  ((Node)o).do_it();
}
Run Code Online (Sandbox Code Playgroud)

  • @JohnRuiz使用`is` +`as`组合导致运行时类型检查执行两次.运行时类型检查通常比简单的"null"检查更昂贵,因此编写代码的更佳方式是`as` +`null`检查.两者都是正确的. (3认同)

dx_*_*_dt 4

从 C# 6(2015 年 7 月)开始,假设Node是 a class(或Nullable<T>string等),使用您的示例

  1. 检查是否o是 a (实际上与转换aNode不同——请参阅下面有关转换与转换的注释)o Node
  2. 如果是这样,请致电do_it()
  3. 立即丢弃强制转换值

您可以使用空条件运算符

(o as Node)?.do_it();
Run Code Online (Sandbox Code Playgroud)

此语法还处理o实际上声明为Node,但碰巧是 的情况null

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

if (o is Node node)
{
    node.do_it();
}
Run Code Online (Sandbox Code Playgroud)

node此时的变量在if语句之外的作用域内,相当于:

Node node = o as Node;
if (node != null) 
{
    node.do_it();
}
Run Code Online (Sandbox Code Playgroud)

因此,如果您只想 ois a时继续执行Node,您可以编写:

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

node.do_it();
// ...
Run Code Online (Sandbox Code Playgroud)

注意:即使您直接指定类型然后询问该变量是否是该类型,is关键字也将始终返回falseif ois 。null

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

node.do_it();
// ...
Run Code Online (Sandbox Code Playgroud)

铸造与转换

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

C# 用户存在一个误用词,即我们交替使用“cast”和“convert”这两个词。这可能源于这样一个事实:我们通常知道基类型变量始终是子类型,因此当严格地我们应该使用强制转换语法时,我们使用转换语法:

string foo = null;
if (foo is string)
{
    // never gets here
    Console.WriteLine(foo);
}
Run Code Online (Sandbox Code Playgroud)

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

转换与转换的不同之处在于内存中的值可能会改变。考虑intdouble

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

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

通过类,我们可以定义自己的隐式和显式运算符,它们将以我们认为合适的方式操作数据。这就是转换转换之间的误用变得混乱的地方。

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

    // explicit converting
    y = 1.5;
    x = (int)y;
}
Run Code Online (Sandbox Code Playgroud)