Подтвердить что ты не робот

С# эквивалентен VB.NET DirectCast?

Есть ли у С# эквивалент VB.NET DirectCast?

Я знаю, что он имеет() casts и ключевое слово 'as', но они выстраиваются в линию до CType и TryCast.

Чтобы быть ясным, эти ключевые слова делают следующее:

CType/() casts: если это уже правильный тип, бросьте его, в противном случае найдите конвертер типов и вызовите его. Если конвертер типа не найден, вызовите InvalidCastException.

TryCast/ "as" ключевое слово: если это правильный тип, произведите его, иначе верните нуль.

DirectCast. Если это правильный тип, бросьте его, в противном случае выведите InvalidCastException.

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

DirectCast допускает только сужение или расширение конверсий в дереве наследования. Он не поддерживает преобразования в разных ветвях типа(), т.е.:

С# - это компиляция и запуск:

//This code uses a type converter to go across an inheritance tree
double d = 10;
int i = (int)d;

VB.NET - это НЕ КОМПЛЕКС

'Direct cast can only go up or down a branch, never across to a different one.
Dim d As Double = 10
Dim i As Integer = DirectCast(d, Integer)

Эквивалент в VB.NET для моего кода на С#: CType:

'This compiles and runs
Dim d As Double = 10
Dim i As Integer = CType(d, Integer)
4b9b3361

Ответ 1

Похоже, что функциональность, которую вы хотите, не в С#. Попробуйте это, хотя...

static T DirectCast<T>(object o, Type type) where T : class
{
    if (!(type.IsInstanceOfType(o)))
    {
        throw new ArgumentException();
    }
    T value = o as T;
    if (value == null && o != null)
    {
        throw new InvalidCastException();
    }
    return value;
}

Или, даже если он отличается от VB, назовите его так:

static T DirectCast<T>(object o) where T : class
{
    T value = o as T;
    if (value == null && o != null)
    {
        throw new InvalidCastException();
    }
    return value;
}

Ответ 2

ВТОРОЕ ОБНОВЛЕНИЕ:

ОК, здесь предложен метод С#, который предположительно делает в основном то, что DirectCast делает в VB.NET.

static T DirectCast<T>(object o) where T : class
{
    T value = o as T;
    if (value == null && o != null)
    {
        throw new InvalidCastException();
    }
    return value;
}

Вот проблемы с описанным выше способом:

  • У него есть ограничение where T : class, которое DirectCast не поддерживает.
  • Он помещает свой аргумент как System.Object - снова, а не true для DirectCast (по крайней мере, не тот, о котором я знаю).
  • Он использует as без необходимости (именно поэтому он имеет ограничение class); call (T) o будет бросать InvalidCastException, если он не работает; зачем проверять, совпадает ли значение с помощью as, только для того, чтобы выбросить то же исключение, которое было бы выброшено, если бы вы отправили маршрут (T)o для начала?

Этот метод действительно можно переписать для получения тех же результатов, что и DirectCast следующим образом:

static T DirectCast<T>(object o) {
    return (T)o;
}

Смешное наблюдение: действительно, весь этот метод делает бокс, а затем пытается его распаковать. Другими словами, DirectCast<int>(12.0) действительно будет таким же, как (int)(object)12.0 (и либо выбросит исключение). Понимая это, предлагаемый метод DirectCast<T> совсем не нужен вообще.

Теперь вот пример того, как DirectCast и кастинг с () являются "разными" между VB.NET и С#:

VB:

Dim i As Integer = 12
Dim l As Long = DirectCast(i, Long) ' does not compile '

С#:

int i = 12;
long l = i; // DOES compile

ОК, поэтому один компилируется, другой - нет. Но посмотрите на этот код. Какая точка DirectCast, когда вы уже знаете тип объекта?. Это не реалистичное сравнение, потому что в VB.NET никогда не было бы причин вызывать DirectCast как код выше делает. (Если вы хотите преобразовать значение, имеющее тип System.Int32, в значение типа System.Int64 в VB.NET, вы должны использовать CLng, а не DirectCast.) Если бы была переменная, напечатанная как System.Object там , тогда было бы целесообразно использовать DirectCast, а приведенный ниже код действительно был бы эквивалентен:

VB:

Dim i As Integer = 12
Dim o As Object = i
Dim l As Long = DirectCast(o, Long) ' compiles, throws an exception '

С#:

int i = 12;
object o = i;
long l = (long)o; // compiles, throws an exception

Поэтому я утверждаю, что DirectCast в VB.NET, в любом сценарии, в котором он имеет смысл использовать его (т.е. когда тип объекта неизвестен во время компиляции), - это то же самое как прямой стиль () в С#.


РЕДАКТИРОВАТЬ. Ну, стыдно за то, что я опубликовал код VB, который не компилировался. Пересмотрев то, что я говорил, я отозвал свой второй ответ, но сохранил первый.

Если вы ссылаетесь на использование DirectCast, где вы берете объект неизвестного типа и пытаетесь применить его к нужному типу, то это то же самое, что и С#() cast:

VB:

Dim o As Object = SomeObject()
Dim i As Integer = DirectCast(o, Integer)

С#:

object o = SomeObject();
int i = (int)o;

Это потому, что если o вводится как System.Object, то операция () в С# будет пытаться распаковать его. Это не удастся, если типы не совпадают точно; например, если o представляет собой коробку System.Double, тогда (int)o генерирует исключение, потому что o должен быть распакован как System.Double, прежде чем он может быть преобразован в System.Int32 (если вы мне не верите, попробуйте сами!).


Примечание: ниже неточно, потому что DirectCast выполняет не выполнение расширений конверсий; в любом случае, я оставляю его для потомков.

С другой стороны, при работе с расширением и сужением конверсий использование операции () в С# делает больше работы, чем просто литье, как вы указали (т.е. вы можете сделать (int)someDouble). В этом случае DirectCast эквивалентно простому старому назначению в С#:

VB:

Dim i As Integer = 12
Dim l As Long = DirectCast(i, Long) ' does not compile, actually '

С#:

int i = 12;
long l = i;

Ответ 3

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

Это фактические эквиваленты:

double d = 10;
int i = (int)d;

Dim d As Double = 10
Dim i As Integer = d

Обратите внимание на опасность этой конструкции, когда вы просто просто назначаете double в integer в VB.NET, двойник будет случайно уменьшен до целого.

В то время как программисты на С# получают безопасность во время компиляции не случайно изменяя переменную .NET. Программистам VB.NET приходится бороться с тем, чтобы всегда устанавливать DirectCast в качестве безопасной привычки программирования.

Это фактические эквиваленты:

// will not compile, cannot convert double to int

double d = 10;
int i = d; 

' will not compile, cannot convert double to int

Dim d As Double = 10
Dim i As Integer = DirectCast(d, Integer) 

[EDIT]

@Дан Тао:

Нет необходимости использовать DirectCast в С#, среда выполнения также предотвращает загрузку значения long в integer. Это то, что csauve утверждает, что у С# нет DirectCast, что DirectCast может предотвратить назначение разных типов переменных, тогда как "потому что" С# не имеет этого DirectCast, он будет молчать при назначении разных типов. Но, как вы можете видеть, это не так, С# кастинг точно такой же, как DirectCast. Это приведет к ошибке InvalidCastException:

long l = 10;
object o = l;
int i = (int)o;

Это также вызовет такую ​​же ошибку времени выполнения, как указано выше:

Dim l As Long = 10
Dim o As Object = l
Dim i As Integer = DirectCast(o, Integer)

Теперь, когда приходит "забавная" часть, с VB.NET вам нужно запомнить много ключевых слов, чтобы что-то выполнить. В С#, если заданное ключевое слово можно использовать в другом сценарии (например, в этом случае с понижением числа переменных), они не будут изобретать другое ключевое слово только для того, чтобы это произошло.

В С# вам просто нужно сделать это:

long l = 10;
object o = l;
int i = (int)(long)o;

В VB.NET, если вы действительно хотите перетащить переменную и хотите ортогональный способ ее выполнения, т.е. просто вспомнить одно ключевое слово, вы должны сделать это:

 Dim l As Long = 10
 Dim o As Object = l
 Dim i As Integer = DirectCast(DirectCast(o, Long), Integer)

Но это не скомпилируется, поэтому как добиться понижения до целого числа? Вы должны помнить другие ключевые слова VB.NET. В то время как в С# он ортогонален, вы используете переменную unbox, используя эту конструкцию (typehere), вы также downcast/upcast, используя ту же конструкцию (typehere). В VB.NET существует принципиальное отключение между загрузкой значения из объекта и его понижением. Поэтому в VB.NET вы должны сделать это:

 Dim l As Long = 10
 Dim o As Object = l
 Dim i As Integer = CType(o, Integer)

Хм.. Я думаю, что csauve путаница проистекает из многократного использования С# (typehere), сначала оно используется для downcasting; во-вторых, тот же самый конструктор (проверьте первую часть этого сообщения, object o = l) также используется для распаковки значения из объекта, которые, как и полагают, имеют поведение преобразования безопасного типа DirectCast, они одинаковы!

Это понижение...

long l = 1;
int i = (int) l;

... не эквивалентен:

Dim l As Long = 1
Dim i As Integer = DirectCast(l, Integer)

Если вы хотите выполнить downcasting, вы должны сделать это:

Dim l As Long = 1
Dim i As Integer = CInt(l) ' can also use CType

Теперь, если программист VB.NET программирует по намерениям и не спит во время кодирования, почему он будет использовать DirectCast, когда он полностью осознает, что он не может назначать разные типы? Если то, что действительно хотел программист VB.NET, - это подавление, он не должен сначала пытаться использовать DirectCast. Теперь программист VB.NET, обнаружив, что DirectCast не может использоваться для downcasting, должен отменить то, что он написал, и заменить его на CInt (или CType)

Ответ 4

Вы можете реализовать его самостоятельно:

static T CastTo<T>(this object obj) { return (T)obj; }

Используется следующим образом:

3.5.CastTo<int>(); //throws InvalidCastException.

Это работает и не включает в себя пользовательские преобразователи из-за того, что генерические файлы "разрешены" во время выполнения, но преобразования типов решаются во время компиляции - структура фактически не генерирует разные реализации для каждого T а скорее использует реализацию для аналогичного T, и, следовательно, среда выполнения не имеет информации для разрешения пользовательских преобразований.

Ответ 5

VB.NET:

Dim xxx as label = Directcast(sender, label)

С#:

label xxx = (label)sender;

Ответ 6

У вас есть два типа трансляции в С#. Без дополнительного кода эквивалент ключевого слова DirectCast в С#. Самое близкое, что вы сами не создаете, это использовать ().

У вас есть:

My_Object c = (My_Object)object

и

My_Object c = object as My_Object

В первом случае, если сбой выполняется, он выдает ошибку. Вы говорите: "Я знаю, что это за объект, а если нет, то что-то не так".

Во втором, c присваивается значение null, где это возможно (null не может быть присвоен типам значений). В этом вы говорите: "Я думаю, что знаю, что это такое, но если не ошибаюсь, потому что ничего не может быть неправильно".

Другое сообщение, объясняющее кастинг:

В чем разница между явным и неявным типом приведения?

Ответ 7

Вы действительно пытались запустить образец кода?

Что касается...

//This code uses a type converter to go across an inheritance tree
string s = "10";
int i = (int)s;

... Вы полагаете, что он будет работать. Он также не работает

Ответ 8

Позвольте мне попытаться сделать снимок.

Во-первых, позвольте мне прояснить это. Этот НЕОБХОДИМО компилировать:

//This code uses a type converter to go across an inheritance tree
string s = "10";
int i = (int)s;

VB CType

В VB вы должны использовать:

Dim s as String = "10"
Dim i as Integer = CType(s, Integer)

В С# я бы использовал:

string s = "10";
int i = Convert.ToInt32(s);

VB DirectCast

Если это правильный тип, бросьте его, иначе бросьте InvalidCastException.

Прямое приведение может только увеличиваться или уменьшаться ветки, никогда не переходя к другому один.

Из этого объяснения это будет прямой эквивалент С# cast. Однако в С# вам нужно будет указать оператора трансляции только для отбрасывания. Отливка полностью необязательна. Пример:

// casting down
object t = "some random string needing to be casted down";
string s = (string) t;
// casting up
object a = s;
// explicitly casting up although it totally optional
object b = (object) s;

С# cast не ищет какой-либо конвертер типов. Он будет искать только определенную явную/неявную перегрузку оператора для типа, который вы пытаетесь выполнить.


VB TryCast

Вы правильно поняли, что это эквивалентно ключевому слову С#.

Ответ 9

Я думаю, что этот сценарий лучше всего подходит, потому что DirectCast имеет ложное представление о проверке безопасности типа времени компиляции для типа объектов, не относящихся к объекту (object keyword), и предназначен только для того, чтобы быть обратно.

float f = 10;
long l = f;

Option Strict On    
Dim f As Single = 10
Dim l As Long = f

С# -кодер, обнаружив, что float не может быть назначен на длительное время и не будет компилироваться, сделает следующее:

long l = (long)f;

Это правильно.

Теперь, вернемся к нашему кодеру VB.NET, обнаружив, что float не назначается долго и не компилируется, попытается это сделать:

Dim l As Long = DirectCast(f, Long)

Через несколько секунд...

Программист VB.Net: "Пожалуйста, позвольте мне сделать мои предложения, пожалуйста, скомпилируйте, пожалуйста...!!!"

После нескольких моментов через GoogleDu и MSDN:

Программист VB.NET: "Ах... поэтому мне нужно использовать эту конструкцию CLng или CType для литья переменных"

Dim l As Long = CLng(f)

Это то, что я имел в виду под DirectCast, имеет ложное представление о безопасности проверки типа компиляции. DirectCast просто должен быть обратным, если программист не знает, когда и где их следует использовать. DirectCast - это защитное одеяло, которое не носится все время.

Насколько полезен DirectCast в этом сценарии, если он не будет использоваться в конце концов?


[EDIT]

@Jules

Я не утверждаю, что все программисты VB.NET не знают, что такое реальное использование DirectCast, некоторые из них действительно знают, что DirectCast предназначены только для использования для типов объектов (и примитивных типов, объект).

Один сценарий, когда кодирование VB.NET, кодирующее существующий код С#, на VB.NET, придет к ошибочному выводу, с ожидаемой (будь то правильно или нет) симметрией языков друг к другу.

Когда он видит в коде эту конструкцию...

TextBox txt = (TextBox)sender;

... Он переведет это:

Dim txt As TextBox = DirectCast(sender, TextBox)

Это правильно.

Теперь, поскольку мы, программисты, любим симметрию, некоторые из нас (может быть, я тоже, если не знаю CLng) будут стремиться преобразовать этот код...

/* numbers are stored in file as float(component file structure 
is designed by 3rd party company) */
float f = file.ReadFloat(0); 
long l = (long)f; // but we don't care about using the fractional part

... к этому:

Dim f As Single = file.ReadFloat(0)
Dim l As Long = DirectCast(f, Long)

Если человек С# является тем, кто преобразует код С# в VB.NET, он будет разочарован очевидным отсутствием симметрии здесь.

Но для человека VB.NET, которому поручено преобразовать код С# в VB.NET, у него создаст впечатление, что компилятор С# не ловит несовместимые назначения типов, а VB.NET ловит его. Теперь, для этого очевидного открытия, похвастает функция VB.NET для его коллег и некоторых форумов.

Но чтобы программист VB.NET не ошибся в ошибочном определении намерения первого кода. Фрагмент кода С# выше начал свою жизнь следующим образом: изначально был написан следующим образом:

float f = file.ReadFloat(0); 
long l = f; 

И это не будет компилироваться, компилятор С# улавливает несовместимые назначения типов, в том же духе, что эквивалентный VB.NET с Option Strict On также не будет компилировать это (хотя он не будет компилироваться, когда Option Strict установлен на On, слишком мягкий). Поэтому нам нужно с помощью (long) использовать тип float для долгого использования. Становится следующим: long l = (long)f;

Теперь для того, чтобы лить один тип переменной в другой совместимый тип, в том же духе, который мы преобразуем в этот код...

TextBox txt = (TextBox)sender;

... к этому коду:

Dim txt As TextBox = DirectCast(sender, TextBox)

Мы должны преобразовать этот код...

long l = (long)f; // will compile

... к этому коду:

Dim l As Long = DirectCast(f, Long) ' will not compile

Но, увы, это не будет скомпилировано при кастовании между совместимыми примитивными типами, в этом случае DirectCast сокращается. Он не предлагает никакой симметрии вышеописанному С# -коду, он не может использоваться для примитивных примитивных типов, несмотря на его название Direct Cast.

Как я вижу, DirectCast следует называть CastObject, так как он может использовать только типы объектов (а также примитивные типы, помещенные в объект). DirectCast действительно не имеет бизнеса с назначением совместимых примитивных типов (integer, double и их более низкий и более высокий аналог). При назначении между совместимыми примитивными типами DirectCast перестает быть полезным, особенно если вы его каким-то образом переместите и замените его на подходящий.

Или другим способом я вижу это, конструкцию DirectCast следует изменить, чтобы он мог отображать совместимые типы, например, как старые и более новые языки, с тех пор, например, C, С++, С#, Java, Delphi, D и т.д. Сделав это, он предложит значительную симметрию VB.NET для других языков, когда дело доходит до литья типов. Делая это, мы также можем выбросить (гипотетически только, мы не можем заставить другие программы терпеть неудачу, полагаясь на старые функции), все множество функций, имена которых непосредственно не сопоставляются с его типами (например, CInt, CDbl, CSng и т.д.), Мы будут использовать DirectCast вместо них.

Ответ 10

DirectCast и () не всегда генерируют один и тот же IL, поэтому я думаю, что это разница между компиляторами VB и С#.

AFAICT, ссылочные типы приводятся с использованием инструкции IL castclass, тогда как для типов значений компилятор генерирует соответствующий IL в зависимости от типов ввода.

В С# приведение от double к integer испускает инструкцию IL conv.i4, которая будет весело перезаписывать знаковый бит или что-либо еще в выводе, если значение слишком велико. В VB это ошибка компиляции.

Интересно, что если вы используете промежуточную переменную object для хранения double, то приведение не удастся как для С#, так и для VB... но во время выполнения. Оба компилятора выдают инструкцию unbox вместо того, чтобы пытаться выполнить преобразование.

Ответ 11

Литье() должно быть одинаковым; он выдает InvalidCastException. Просто попробуйте это на С#:

 string t = "hello";
 object x = t;
 int j = (int) x;