Что такое C # эквивалентно C ++'s dynamic_cast? - PullRequest
10 голосов
/ 16 февраля 2012

Этот код C ++ проверяет, является ли o значением Node * и, если это так, вызывает метод для d.

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

. Какой самый короткий и / или наиболее эффективный способ написать эквивалентв C #?

Ответы [ 4 ]

20 голосов
/ 16 февраля 2012

Предполагая, что Node является class, выполните следующее

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

Если вместо этого struct, попробуйте это

if (o is Node) {
  ((Node)o).do_it();
}
2 голосов
/ 13 июля 2018

Начиная с C # 6 (июль 2015 г.), предполагая, что Node - это class (или Nullable<T>, string и т. Д.), Используя ваш пример, где вы

  1. проверьте, является ли o Node (на самом деле не то же самое, что преобразование o в a Node - см. Примечание о приведении к преобразованию ниже)
  2. если это так, звоните do_it()
  3. немедленно отбрасывает приведенное значение

Вы можете использовать нулевой условный оператор :

(o as Node)?.do_it();

Этот синтаксис также обрабатывает случай, когда o фактически объявлен как Node, но бывает null.

Если вы хотите сохранить переменную приведения, начиная с C # 7 (март 2017 г.), вы можете запустить:

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

Переменная node на данный момент находится в области действия вне оператора if, что эквивалентно:

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

Итак, если вы хотите продолжить выполнение , если o равно Node, вы можете написать:

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

node.do_it();
// ...

Примечание. Ключевое слово is будет всегда возвращать false, если o равно null, даже если вы прямо указали тип, а затем спросите, является ли эта переменная этим типом.

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

Кастинг против Конвертации

Ключевые слова is и as делают то же самое, что и dynamic_cast<T> в C ++: они проверяют указанный тип, подтип или интерфейс, но фактически не изменяют значение в памяти. Они просто сообщают компилятору, какие методы должны быть доступны для переменной.

Среди пользователей C # есть неправильное выражение: мы используем слова «cast» и «convert» взаимозаменяемо. Вероятно, это связано с тем, что мы часто знаем , что переменная базового типа всегда будет подтипом, и поэтому мы используем синтаксис convert , когда по-пуритански нам следует использовать приведение синтаксис:

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

Этот синтаксис генерирует во время выполнения, если value на самом деле не MySubType.

Преобразование отличается от преобразования тем, что значение в памяти может измениться. Рассмотрим int и double.

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

    // explicit converting
    y = 1.5;
    x = (int)y;
}

В каждом из этих случаев литеральное значение, хранящееся в памяти, изменяет формат. int s всегда можно представить как double - данные никогда не будут потеряны - и поэтому существует определенный implicit operator, который будет манипулировать данными в памяти в новом формате. double s, будучи значениями с плавающей запятой и имеющими диапазон больше int s, не может гарантировать отсутствие потери данных, поэтому C # требует явного преобразования (обычно называемого «явным приведением») через explicit operator, чтобы указать компилятор, что мы в порядке с потерей данных.

С помощью классов мы можем определить наши собственные неявные и явные операторы, которые будут манипулировать данными любым удобным для нас способом. Это где неправильное число между преобразовать и приведение становится грязным.

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;
    }
}
1 голос
/ 16 февраля 2012

Оператор as возвращает ноль, если o не является Node:

Node d = o as Node;
if (d != null)
{
    d.do_it();
}
0 голосов
/ 16 февраля 2012

Вы можете использовать ключевое слово is в C #.

if (o is Node) 
{

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...