Я думаю, что этот сценарий лучше всего объясняет, почему 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: «Пожалуйста, позвольте мне делать ставки, пожалуйста, скомпилируйте, пожалуйста ... !!!»
После некоторых моментов, связанных с поиском в Google и MSDN:
Программист VB.NET: «Ах .. поэтому я должен использовать эту конструкцию CLng или CType для приведения переменных»
Dim l As Long = CLng(f)
Это то, что я имел в виду под DirectCast, имеет ложное чувство безопасности проверки типов во время компиляции. DirectCast просто предназначен для возврата, если программист не знает, когда и где их следует использовать. DirectCast - это защитное одеяло, которое не носят постоянно.
Насколько полезен DirectCast в этом сценарии, если он вообще не будет использоваться?
[EDIT]
@ 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 вместо них.