Эквивалент C # DirectCast в VB.NET

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

Я знаю, что у него есть приведение типов () и ключевое слово as, но они соответствуют CType и TryCast.

Для ясности, эти ключевые слова делают следующее;

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

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

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

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

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

C # - это компилируется и запускается:

//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)

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

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

person csauve    schedule 21.04.2010    source источник
comment
+1 за определение ключевых слов, а не за то, чтобы люди искали его.   -  person Greg    schedule 21.04.2010
comment
string s = "10"; int i = (int)s; не компилируется на C #.   -  person Robert Davis    schedule 21.04.2010
comment
Вы пробовали использовать отражатель для сравнения MSIL?   -  person stevehipwell    schedule 21.04.2010
comment
@ Роберт: Ой! Я переписал с помощью double ... и на этот раз фактически прогнал свой код через компиляторы :)   -  person csauve    schedule 21.04.2010
comment
@ Роберт Дэвис: я думаю, что Коллин Суаве не пытается запустить в Visual Studio свои предположения   -  person Michael Buen    schedule 21.04.2010
comment
@csauve: Вы ошибаетесь насчет того, что делают ключевые слова. Хотя int i = (int)d; может выполнять известное преобразование для известного типа, как в вашем примере кода, в любом сценарии, где вы реалистично использовали бы DirectCast в VB.NET (т. Е. Когда тип объекта неизвестен при компиляции time), приведение с () в C # не выполняет преобразование - оно просто выполняет приведение. Таким образом, двойное число в штучной упаковке не может быть распаковано как целое число. По этой причине они фактически эквивалентны.   -  person Dan Tao    schedule 21.04.2010
comment
@csauve: В приведенном вами примере DirectCast - это ложное защитное одеяло, которое не носят постоянно. Прежде всего, если вам действительно нужно преобразовать переменную к другому совместимому типу, DirectCast бесполезен. См. Мое сообщение здесь: stackoverflow .com / questions / 2683847 /.   -  person Michael Buen    schedule 21.04.2010
comment
Думаю, вас может заинтересовать System.Type метод IsAssignableFrom.   -  person Michael Petito    schedule 22.04.2010
comment
Из любопытства, зачем вам это нужно?   -  person RCIX    schedule 22.04.2010
comment
Ваши утверждения о том, что () отличается от DirectCast, верны для типов значений, но неверны для типов ссылочных. [Эти два эквивалента для ссылочных типов; преобразование не выполняется.] Это делает сравнение бессмысленным, потому что, IMHO, нет причин использовать DirectCast с типом value. Как я это вижу: () эквивалентно CType для типов значений и DirectCast для ссылочных типов.   -  person ToolmakerSteve    schedule 18.04.2018


Ответы (11)


Кажется очевидным, что нужной вам функциональности нет в C #. Хотя попробуйте это ...

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;
}
person Greg Bogumil    schedule 21.04.2010
comment
согласен с тем, что я думал изначально. Спасибо. - person csauve; 21.04.2010
comment
Вы можете удалить требование T : class, если используете is вместо as. static T DirectCast<T>(object o) { if(o != null && o is T) return (T)o; else throw new InvalidCastException(); } - person Robert Davis; 21.04.2010
comment
В вашем коде вы не используете параметр типа, поэтому можете не указывать его. Или используйте его для дополнительной проверки: if (typeof (T)! = Type) throw new InvalidArgumentException (...) ;. - person Hans Kesting; 21.04.2010
comment
Я просто заметил тот же факт. - person Greg Bogumil; 21.04.2010
comment
@ Роберт Дэвис: Класс where T: там, так что я могу использовать «как». Использование return (T) o, похоже, идет вразрез с тем, чего хочет добиться csuave. - person Greg Bogumil; 21.04.2010
comment
@gbogumil, я бы согласился с Робертом в этом, вы можете использовать return (T) o в этот момент, потому что вы можете быть абсолютно уверены, что o есть T. конверсии. - person csauve; 21.04.2010
comment
Я считаю, что эквивалент DirectCast на самом деле доступен в C # - просто разделен на два разных использования в зависимости от сценария. Смотрите мой ответ. - person Dan Tao; 21.04.2010
comment
@gbogumil: Я не хочу быть антагонистом, но я думаю, что этот ответ вводит в заблуждение и упускает из виду истинную взаимосвязь между DirectCast в VB.NET и приведением типов в C #. Взгляните на мой ответ и дайте мне знать, что вы думаете. - person Dan Tao; 21.04.2010
comment
@ Роберт Дэвис: На самом деле проверки типов для o не нужны вообще, поскольку (T)o уже выдаст InvalidCastException, если типы не совпадают. Имея это в виду, реальный эквивалентный код будет просто return (T)o;, что дает понять, что сам метод может быть просто эквивалентом (T)(object)value. Посмотри на мой ответ. - person Dan Tao; 21.04.2010
comment
@ Дэн Тао: Ты прав. Поскольку тип не может создать неявный / явный оператор из объекта, (T)(object)value никогда не будет вызывать никаких функций преобразования. - person Robert Davis; 22.04.2010
comment
Я не думаю, что type is T проверка делает то, что вы думаете. На самом деле это совершенно неправильно. Вероятно, вы ищете type.IsInstanceOfType(o). Комбинирование is с as также излишне. - person Aaronaught; 22.04.2010
comment
Этот ответ действительно вводит в заблуждение. Когда !(type is T) когда-либо возвращает истину ?? Ответ: наверное, не тогда, когда думаешь. Этот оператор фактически проверяет, когда T не является базовым классом или интерфейсом System.Type (не соответствующим типом, указанным экземпляром type, что, как я думаю, было намерением). - person Michael Petito; 22.04.2010
comment
При работе с ссылочными типами, C # (SomeReferenceType) равен DirectCast. См. Операция приведения между ссылочными типами не изменяет тип времени выполнения базового объекта; ... в документах. microsoft.com/en-us/dotnet/csharp/programming-guide/types/. То есть для типов ссылочных этот синтаксис никогда не выполняет никаких преобразований. Следовательно, учитывая, что у вас есть ограничение where T : class, в этом коде нет необходимости; просто используйте (SomeReferenceType) - person ToolmakerSteve; 18.04.2018

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

Хорошо, вот метод C #, который был предложен для выполнения в основном того же, что 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;
}

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

  1. У него есть where T : class ограничение, которого DirectCast нет.
  2. Он помещает свой аргумент как System.Object - опять же, неверно для DirectCast (по крайней мере, я не знаю).
  3. Он использует as без надобности (именно поэтому в первую очередь имеет ограничение class); вызов (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 и C #:

VB:

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

C#:

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 '

C#:

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

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


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

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

VB:

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

C#:

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

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


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

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

VB:

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

C#:

int i = 12;
long l = i;
person Dan Tao    schedule 21.04.2010
comment
Ваш код vb не компилируется. Я предполагаю, что вместо 12 в качестве параметра типа для прямой трансляции вы имели в виду long, но это тоже не компилируется. Также убедитесь, что опция strict включена, иначе вы получите кучу неявных преобразований (компилятор vb любит читать мысли) - person csauve; 21.04.2010
comment
@csauve: Хороший звонок. Это было глупо с моей стороны! В любом случае взгляните на мою первую мысль. Я верю, что DirectCast действительно совпадает с операцией () в C # при использовании с объектами, набранными как System.Object. - person Dan Tao; 21.04.2010
comment
@csauve: Кстати, что касается Option Strict ... в коде, который я изначально опубликовал, Option Infer работает точно так же. (Я все равно добавил типы для полноты.) - person Dan Tao; 21.04.2010

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

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

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

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

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

person Eamon Nerbonne    schedule 21.04.2010

VB.NET:

Dim xxx as label = Directcast(sender, label)

C#:

label xxx = (label)sender;
person Willian Ernesto Sandoval    schedule 28.08.2019
comment
Добро пожаловать в StackOverflow. пожалуйста, объясните свой код и то, как этот код решает проблему. - person Mehdi Yeganeh; 28.08.2019
comment
Вам следует прочитать вопрос полностью, а также существующие ответы, когда вы некроите вопрос 8-летней давности. - person csauve; 29.08.2019

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

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

double d = 10;
int i = (int)d;
Dim d As Double = 10
Dim i As Integer = d

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

В то время как программисты на C # получают безопасность во время компиляции, поскольку случайно не уменьшат размер переменной в .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)

Что касается комментария Дэна Тао:

В C # нет необходимости использовать DirectCast. Среда выполнения также предотвращает загрузку длинных целочисленных значений. Это то, что утверждает OP, что C # не имеет DirectCast, что DirectCast может предотвратить назначение различных типов переменных, тогда как, поскольку C # не имеет этого DirectCast, он будет молча ошибаться при назначении разных типов. Но, как видите, это не так. Приведение в C # в точности совпадает с 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 вам нужно запомнить множество ключевых слов, чтобы чего-то добиться. В C #, если данное ключевое слово может использоваться в другом сценарии (как в этом понижающем преобразовании переменной), они не будут изобретать другое ключевое слово только для того, чтобы это произошло.

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

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. В то время как в C # он ортогонален, вы распаковываете переменную, используя эту конструкцию (typehere), вы также понижаете / повышаете, используя ту же конструкцию (typehere). В VB.NET существует фундаментальная пропасть между загрузкой значения из объекта и его понижением. Итак, в VB.NET вы должны сделать это:

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

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

Это опускание ...

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

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

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

Если вы хотите выполнить приведение вниз, вам нужно сделать это:

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

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

person Michael Buen    schedule 21.04.2010
comment
Попробуйте включить Option Strict - я надеюсь, что большинство магазинов заставят любых разработчиков vb писать с ним. - person csauve; 21.04.2010
comment
@Michael: Я тоже так думал; но, как указал csauve в комментарии к моему ответу, примеры кода в конце вашего ответа на самом деле не эквиваленты. long можно назначить int в C #, но VB.NET не позволит назначить Long Integer с помощью DirectCast. - person Dan Tao; 21.04.2010
comment
@Dan Tao - См. Мой комментарий выше - person Michael Buen; 21.04.2010
comment
Наши ответы несколько сошлись;) Но моя точка зрения была конкретно в ответ на ваш код double d = 10; int i = d; - вы правильно заметили, что он не будет компилироваться, как и DirectCast(d, Integer) не будет компилироваться; с другой стороны, в C # int i = 10; long l = i; будет компилироваться на C #, а DirectCast(i, Long) - нет. В остальном, я думаю, мы полностью на одной странице. - person Dan Tao; 21.04.2010
comment
@ Дэн Тао: по поводу DirectCast (я, Лонг). Я думаю, что разработчики языка VB.NET не хотят, чтобы их программисты страдали. Почему они не позволят программистам VB.NET использовать это (они позволяют)? - ›Dim l As Long = i. Я думаю, что в целом DirectCast просто предназначены для возврата, когда они случайно используются (из-за неправильного ожидания использования) программистами, когда в действительности они имели в виду CInt / CLng, CType и т. Д. - person Michael Buen; 21.04.2010

Позвольте мне попробовать сделать это.

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

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

VB's CType

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

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

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

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

DirectCast от VB

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

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

Исходя из этого объяснения, это был бы прямой эквивалент преобразования C #. Однако в C # вам нужно будет указать только оператор приведения только для приведения. Кастинг совершенно не обязателен. Пример:

// 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's totally optional
object b = (object) s;

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


TryCast от VB

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

person Amry    schedule 21.04.2010
comment
Приведение C # () позволяет преобразователи типов. DirectCast этого не делает. Замените строку на двойную, и вы увидите. C # позволяет использовать double- ›int с помощью () cast, vb.net не позволяет использовать прямое преобразование, только ctype. - person csauve; 21.04.2010
comment
() cast не использует преобразователи типов. Он действует на интерфейсе IConvertible. Убедитесь сами на странице MSDN TypeConverter: msdn.microsoft.com/ ru-ru / library /. Нет ни одного примера, показывающего, что вы можете использовать приведение C # для запуска использования TypeConverters. - person Amry; 21.04.2010
comment
Вы правы, и я ошибался, что приведение C # не ищет никаких преобразователей типов. Он будет искать только любую определенную явную / неявную перегрузку оператора для типа, к которому вы пытаетесь привести. Что делает его самостоятельным - это не совсем ctype и не совсем прямая трансляция. - person csauve; 21.04.2010

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

У вас есть:

My_Object c = (My_Object)object

и

My_Object c = object as My_Object

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

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

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

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

person kemiller2002    schedule 21.04.2010
comment
ой, я перепутала терминологию. Спасибо - person kemiller2002; 21.04.2010
comment
Как указано выше, приведение типов () допускает преобразователи типов, а DirectCast - нет. - person csauve; 21.04.2010

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

Касательно...

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

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

person Community    schedule 21.04.2010
comment
Я отредактировал его, чтобы использовать двойные. У меня было неверное представление о том, что строка- ›int разрешена в C #. двойной- ›int shoudl work - person csauve; 21.04.2010

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

float f = 10;
long l = f;
Option Strict On
Dim f As Single = 10
Dim l As Long = f

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

long l = (long)f;

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

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

Dim l As Long = DirectCast(f, Long)

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

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

Спустя некоторое время после просмотра Googling-fu и MSDN:

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

Dim l As Long = CLng(f)

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

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


[РЕДАКТИРОВАТЬ]

@Jules

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

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

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

TextBox txt = (TextBox)sender;

... Он / она переведет это на следующее:

Dim txt As TextBox = DirectCast(sender, TextBox)

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

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

/* Numbers are stored in file as float(component's 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)

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

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

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

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

И это не будет компилироваться, компилятор C # улавливает несовместимые присвоения типов в том же духе, что эквивалентный VB.NET с Option Strict On также не будет компилировать это (хотя не будет компилироваться только тогда, когда Option Strict установлено в On, слишком снисходительный). Итак, нам нужно привести тип float к long, используя (long). Становится так: 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 проигрывает. Он не предлагает никакой симметрии по сравнению с приведенным выше кодом C # и не может использоваться для преобразования совместимых примитивных типов, несмотря на его название Direct Cast .

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

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

person Michael Buen    schedule 21.04.2010
comment
О чем ты говоришь?? Я точно знаю, когда и когда не использовать DirectCast. Вы также можете сказать, что кодер VB.Net набирает: Dim l as long = Gosub (f, Long)! - person Jules; 21.04.2010

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

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

В C # преобразование из double в integer генерирует инструкцию conv.i4 CIL, которая с радостью перезаписывает бит знака или что-то еще в выводе, если значение слишком велико. В Visual Basic это ошибка компиляции.

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

person SSS    schedule 19.09.2018

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

 string t = "hello";
 object x = t;
 int j = (int) x;
person Mike_G    schedule 21.04.2010
comment
Да, но (int) x на самом деле пытается преобразовать строку в int, поэтому, если t = 10, это будет успешно. DirectCast не поддерживает преобразователи типов, поэтому даже при t = 10 он все равно не сработает. - person csauve; 21.04.2010
comment
@Collin Sauve: Я не уверен, откуда у вас эта идея, но это неверно. Он просто не будет компилироваться, если вы попытаетесь выполнить int j = (int) t, где t = 10. - person Amry; 21.04.2010
comment
Извините. строки - просто плохой пример. double- ›int - лучше. двойной d = 10; int i = (int) d; это все хорошо и хорошо в С #, но если я заменю (int) d на directcast (d, integer), он не будет работать в vb.net - person csauve; 21.04.2010
comment
Я думаю, что Коллин Сове не пытается запустить предполагаемый не-аналог C # из VB.NET. Если t = 10 (строка), приведенный выше код также приведет к InvalidCastException. @CollinSauve: пожалуйста, запустите код в Visual Studio, прежде чем делать предположения - person Michael Buen; 21.04.2010