В блогах по разработке, онлайн-примерах кода и (в последнее время) даже в книге я постоянно спотыкаюсь о коде:
var y = x as T;
y.SomeMethod();
или, что еще хуже:
(x as T).SomeMethod();
Это не имеет смысла для меня. Если вы уверены , что x
это типа T
, вы должны использовать прямой бросок: (T)x
. Если вы не уверены, вы можете использовать, as
но нужно проверить null
перед выполнением какой-либо операции. Все, что делает приведенный выше код, это превращает (полезное) InvalidCastException
в (бесполезное) NullReferenceException
.
Я единственный, кто считает, что это вопиющее злоупотребление as
ключевым словом? Или я упустил что-то очевидное, и приведенная выше схема действительно имеет смысл?
c#
casting
type-conversion
Heinzi
источник
источник
((T)x).SomeMethod()
, не так ли? ;) (шучу, ты прав конечно!)(f as T).SomeMethod()
Ответы:
Ваше понимание верно. Это звучит как попытка микрооптимизации для меня. Вы должны использовать обычное приведение, когда вы уверены в типе. Помимо генерации более разумного исключения, оно также быстро дает сбой. Если вы ошибаетесь в своем предположении о типе, ваша программа немедленно завершится сбоем, и вы сможете сразу увидеть причину сбоя, а не ждать
NullReferenceException
илиArgumentNullException
даже логической ошибки в будущем. Как правило,as
выражение, за которым не следуетnull
проверка, является запахом кода.С другой стороны, если вы не уверены в касте и ожидаете, что он потерпит неудачу, вы должны использовать
as
вместо обычного броска, обернутогоtry-catch
блоком. Кроме того,as
рекомендуется использование над проверкой типа, сопровождаемой приведением. Вместо:который генерирует
isinst
инструкцию дляis
ключевого слова иcastclass
инструкцию для приведения (эффективно выполняя приведение дважды), вы должны использовать:Это только генерирует
isinst
инструкцию. У первого метода есть потенциальный недостаток в многопоточных приложениях, так как условие гонки может привести к тому, что переменная изменит свой тип послеis
успешной проверки и потерпит неудачу на линии преобразования . Последний метод не подвержен этой ошибке.Следующее решение не рекомендуется для использования в производственном коде. Если вы действительно ненавидите такую фундаментальную конструкцию в C #, вы можете подумать о переходе на VB или другой язык.
В случае, если кто-то отчаянно ненавидит синтаксис преобразования, он / она может написать метод расширения для имитации преобразования:
и используйте аккуратный синтаксис [?]:
источник
cache
объект, который другой поток пытается сделать недействительным, установив егоnull
. В сценариях без блокировки такие вещи могут возникать.Object
. Использование метода для типа значения приведет к тому, что он будет упакован без необходимости.To
метода здесь, поскольку он конвертирует только через иерархию наследования, которая для типов значений в любом случае включает в себя упаковку. Конечно, вся идея скорее теоретическая, чем серьезная.ИМХО,
as
просто имеет смысл в сочетании сnull
проверкойисточник
Использование «как» не применяет определенные пользователем преобразования, в то время как приведение будет использовать их там, где это необходимо. Это может быть важным отличием в некоторых случаях.
источник
Я написал немного об этом здесь:
http://blogs.msdn.com/ericlippert/archive/2009/10/08/what-s-the-difference-between-as-and-cast-operators.aspx
Я понимаю вашу точку зрения. И я согласен с этим: оператор приведения сообщает: «Я уверен, что этот объект может быть преобразован в этот тип, и я готов рискнуть исключением, если ошибаюсь», тогда как оператор «как» сообщает «Я не уверен, что этот объект можно преобразовать в этот тип; если я ошибаюсь, дайте мне ноль».
Тем не менее, есть небольшая разница. (x как T). Что бы ни () сообщало: «Я знаю не только то, что x можно преобразовать в T, но, кроме того, это включает в себя только ссылочные или распаковывающие преобразования, и, кроме того, что x не является нулевым». Это действительно передает информацию, отличную от ((T) x) .Wh независимо (), и, возможно, именно это намеревается автор кода.
источник
((T)x).Whatever()
также сообщает, чтоx
это [не должно быть] пустым, и я очень сомневаюсь, что автору, как правило, будет интересно,T
происходит ли преобразование только с ссылочными или распакованными преобразованиями, или требуется ли преобразование, определяемое пользователем или изменяющее представление. В конце концов, если я определюсьpublic static explicit operator Foo(Bar b){}
, то, несомненно, мое намерениеBar
будет считаться совместимым сFoo
. Я редко хотел бы избежать этого преобразования.Я часто видел ссылки на эту вводящую в заблуждение статью как свидетельство того, что «как» быстрее, чем приведение.
Одним из наиболее очевидных вводящих в заблуждение аспектов этой статьи является график, который не указывает, что измеряется: я подозреваю, что он измеряет неудачные приведения (где «как», очевидно, намного быстрее, поскольку не выбрасывается исключение).
Если вы потратите время на измерения, то увидите, что приведение происходит, как и следовало ожидать, быстрее, чем «как», когда приведение успешно.
Я подозреваю, что это может быть одной из причин "культа груза" использования ключевого слова as вместо приведения.
источник
Прямое приведение требует пары скобок больше, чем
as
ключевое слово. Так что даже в том случае, если вы на 100% уверены, что это за тип, это уменьшает визуальный беспорядок.Договорились об исключении, хотя. Но, по крайней мере, для меня, большинство применений
as
сводятся к тому, чтобыnull
потом проверить , что для меня лучше, чем поймать исключение.источник
99% времени, когда я использую «как», это когда я не уверен, какой тип объекта на самом деле
и я не хочу ни отлавливать явные исключения приведения, ни делать приведения дважды, используя «is»:
источник
as
. Какой еще 1%?Это просто потому, что людям нравится, как это выглядит, это очень читабельно.
Посмотрим правде в глаза: оператор приведения / преобразования в C-подобных языках довольно ужасен с точки зрения читаемости. Я хотел бы лучше, если бы C # принял любой синтаксис Javascript:
Или определите
to
оператор, эквивалент преобразованияas
:источник
dynamic_cast<>()
(и тому подобное). Вы делаете что-то уродливое, это должно выглядеть уродливо.Людям
as
так нравится, потому что это заставляет их чувствовать себя в безопасности от исключений ... Как гарантия на коробке. Парень ставит на коробку причудливую гарантию, потому что хочет, чтобы внутри вас было тепло и жарко. Вы полагаете, что положили эту маленькую коробочку под подушку ночью, Фея Гарантии может спуститься и уйти через четверть, я прав, Тед?Вернемся к теме ... при использовании прямого приведения существует вероятность недопустимого исключения приведения. Таким образом, люди применяют
as
в качестве общего решения для всех своих потребностей в кастинге, потому чтоas
(само по себе) никогда не вызовут исключения. Но забавно то, что в приведенном вами примере(x as T).SomeMethod();
вы заменяете недопустимое исключение приведения на исключение нулевой ссылки. Что скрывает реальную проблему, когда вы видите исключение.Я обычно не использую
as
слишком много. Я предпочитаюis
тест, потому что для меня он кажется более читабельным и имеет больше смысла, чем попытка приведения и проверка на ноль.источник
as
в качестве общего решения, потому что оно заставляет их чувствовать себя в безопасности.Это должно быть одним из моих главных раздражителей .
D & E Страуструпа и / или какой-то пост в блоге, который я не могу найти прямо сейчас, обсуждает понятие
to
оператора, который бы обращал внимание на точку зрения https://stackoverflow.com/users/73070/johannes-rossel (т. Е. Тот же синтаксис, что иas
сDirectCast
семантикой ).Причина, по которой это не было реализовано, заключается в том, что приведение должно причинять боль и быть уродливым, поэтому вы отталкиваетесь от его использования.
Жаль, что «умные» программисты (часто авторы книг (Ювал Лоуи IIRC)) обходят это, злоупотребляя
as
этим способом (C ++ не предлагаетas
, вероятно, по этой причине).Даже VB обладает большей последовательностью, имея единый синтаксис, который заставляет вас выбирать «
TryCast
или»DirectCast
и принимать решение !источник
DirectCast
поведение , а не синтаксис .semantics
вместо этого: Pdouble-to-int
броска, который потерпел бы неудачу, еслиdouble
бы не представлял точное значение, которое могло бы поместиться вInt32
, но иметь(int)-1.5
выход -1 просто ужасно.MaybeValid<T>
с двумя открытыми полямиIsValid
иValue
какой код можно было бы использовать по своему усмотрению. Это позволило бы, напримерMaybeValid<TValue> TryGetValue(TKey key) { var ret = default(MaybeValid<TValue>); ret.IsValid = dict.TryGetValue(key, out ret.Value); return ret; }
. Это не только сэкономит как минимум две операции копирования по сравнению с нимNullable<T>
, но также может быть полезно для любого типа -T
не только для классов.Я считаю, что это
as
ключевое слово можно считать более элегантно выглядящей версиейdynamic_cast
из C ++.источник
dynamic_cast
на C ++.std::bad_cast
.static_cast
выполняет проверку типов во время выполнения. В C # подобного не происходит.Вероятно, он более популярен не по техническим причинам, а только потому, что его легче читать и он более интуитивно понятен. (Не говорю, что это лучше, просто пытаясь ответить на вопрос)
источник
Одна из причин использования «как»:
Вместо (плохой код):
источник
obj
означало бы изменение самойobj
переменной для хранения ссылки на другой объект. Это не изменит содержимое памяти, в которой находится объект, на который изначально ссылаетсяobj
. Этот исходный объект останется неизменным, аt
переменная все равно будет содержать ссылку на него.