開発ブログ、オンラインコード例、そして(最近)本でも、私はこのようなコードについてつまずき続けています。
var y = x as T;
y.SomeMethod();
または、さらに悪いこと:
(x as T).SomeMethod();
それは私には意味がありません。 x
のタイプがT
であることが確実な場合は、直接キャスト(T)x
を使用する必要があります。わからない場合は、as
を使用できますが、何らかの操作を実行する前にnull
を確認する必要があります。上記のコードは、(有用な)InvalidCastException
を(役に立たない)NullReferenceException
に変えるだけです。
これがas
キーワードの露骨な乱用だと思うのは私だけですか?または、明白な何かを見逃し、上記のパターンは実際に理にかなっていますか?
あなたの理解は真実です。それは私に微最適化しようとしているように聞こえます。タイプが確実な場合は、通常のキャストを使用する必要があります。より賢明な例外を生成することに加えて、高速に失敗します。型についての仮定が間違っている場合、プログラムはすぐに失敗し、NullReferenceException
またはArgumentNullException
または論理的なものを待つのではなく、失敗の原因をすぐに確認できます。将来のエラー。一般に、どこかにas
チェックが続かないnull
式はコードのにおいです。
一方、キャストについて確信が持てず、失敗すると予想される場合は、try-catch
ブロックでラップされた通常のキャストの代わりにas
を使用する必要があります。さらに、型チェックの後にキャストが続く場合は、as
を使用することをお勧めします。の代わりに:
if (x is SomeType)
((SomeType)x).SomeMethod();
これは、isinst
キーワードに対して is
命令 を生成し、キャストに対して castclass
命令 を生成します(キャストを2回効果的に実行します) 、使用する必要があります:
var v = x as SomeType;
if (v != null)
v.SomeMethod();
これは、isinst
命令のみを生成します。前者の方法には、マルチスレッドアプリケーションで潜在的な欠陥があります。競合状態により、is
チェックが成功し、キャストラインで失敗した後に変数のタイプが変更される可能性があるためです。後者の方法では、このエラーは発生しません。
次の解決策は、推奨されません本番コードでの使用です。 C#でこのような基本的な構造が本当に嫌いな場合は、VBまたは他の言語に切り替えることを検討してください。
キャスト構文を必死に嫌う場合、キャストを模倣する拡張メソッドを作成できます。
public static T To<T>(this object o) { // Name it as you like: As, Cast, To, ...
return (T)o;
}
そして、きちんとした[?]構文を使用します。
obj.To<SomeType>().SomeMethod()
私見、as
は、null
チェックと組み合わせると意味があります。
var y = x as T;
if (y != null)
y.SomeMethod();
「as」を使用してもユーザー定義の変換は適用されませんが、キャストは必要に応じて変換を使用します。これは、場合によっては重要な違いになります。
私はこれについて少しここに書いた:
私はあなたの主張を理解しています。そして、私はそれの推力に同意します:キャスト演算子は「このオブジェクトをその型に変換できることを確信しており、間違っている場合は例外を危険にさらします」と通信しますが、「as」演算子は「このオブジェクトをその型に変換できるかどうかはわかりません。間違っている場合はnullを指定してください」.
ただし、微妙な違いがあります。 (x as T).whatever()は、「xがTに変換できることだけでなく、参照またはボックス化解除の変換のみが必要であり、さらにxがnullではないことを知っています」と伝えます。それは((T)x).Whatever()とは異なる情報を伝えます。そしておそらくそれはコードの作者が意図していることです。
この誤解を招く記事 への参照は、「as」がキャストよりも速いという証拠としてよく見かけます。
この記事のより明白な誤解を招く側面の1つは、測定対象を示すものではないグラフィックです。failedcasts(where " as "は例外がスローされないため明らかに高速です)。
時間をかけて測定を行うと、予想どおり、キャストが「as」よりもfasterであることがわかります。キャストが成功します。
これが、キャストではなくasキーワードを「カーゴカルト」で使用する理由の1つであると思われます。
直接キャストには、as
キーワードよりも多くの括弧が必要です。したがって、タイプが100%確実である場合でも、視覚的な混乱が軽減されます。
ただし、例外的なことに同意しました。しかし、少なくとも私にとっては、as
のほとんどの使用法は、後でnull
をチェックするために要約されます。これは、例外をキャッチするよりも優れています。
人々がその見た目を好むからといって、とても読みやすいです。
それに直面してみましょう:Cライクな言語のキャスト/変換演算子は、非常にひどく、読みやすいです。 C#が次のJavascript構文のいずれかを採用している場合、私はそれをより良くしたいと思います。
object o = 1;
int i = int(o);
または、to
演算子を定義します。これは、as
と同等のキャストです。
object o = 1;
int i = o to int;
「as」を使用するときの99%は、実際のオブジェクトタイプがわからないときです
var x = obj as T;
if(x != null){
//x was type T!
}
そして、「is」を使用して、明示的なキャスト例外をキャッチしたり、2回キャストしたりしたくありません。
//I don't like this
if(obj is T){
var x = (T)obj;
}
人々は、as
が好きです。なぜなら、例外から安全に感じられるからです...箱の保証のように。ある人は、箱の中に豪華な保証を付けています。なぜなら、彼はあなたに、すべてを温かくて乾杯させたいと思っているからです。あなたは夜に枕の下にその小さな箱を置いたと思います、保証の妖精が降りて四分の一を残すかもしれません、私は正しいテッドですか?
トピックに戻る...直接キャストを使用する場合、無効なキャスト例外にはpossibilityがあります。したがって、as
(単独で)は例外をスローしないため、人々はas
をキャスティングニーズのすべてに包括的なソリューションとして適用します。しかし、それに関する面白いことは、あなたが(x as T).SomeMethod();
を与えた例では、無効なキャスト例外をnull参照例外と交換しているということです。例外が表示されると、実際の問題がわかりにくくなります。
通常、as
はあまり使いません。私にはis
テストが好きです。なぜなら、私にとっては、キャストを試みてnullをチェックするよりも読みやすく、より理にかなっているからです。
これは、私の top peeves のいずれかでなければなりません。
StroustrupのD&Eおよび/または私が今見つけることができないいくつかのブログ記事は、 https://stackoverflow.com/users/73070/johannes-rosselによって作られたポイントに対処するto
演算子の概念を議論しています (つまり、as
と同じ構文ですが、DirectCast
セマンティクスを使用します)。
これが実装されなかった理由は、キャストが苦痛を引き起こし、いために使用をやめられるためです。
「賢い」プログラマー(本の著者(Juval Lowy IIRC))がこの方法でas
を悪用することでこれを回避しているのは残念です(C++はおそらくこの理由でas
を提供しません)。
VBでさえ、TryCast
またはDirectCast
を選択するように強制する統一された構文を持つことで、より一貫性があり、心を決めます!
as
キーワードは、C++のdynamic_cast
のよりエレガントなバージョンと考えることができます。
技術的な理由はないが、読みやすく直感的だという理由だけで、おそらくより人気があります。 (質問に答えるだけで良くなるとは言わない)
「as」を使用する1つの理由:
T t = obj as T;
//some other thread changes obj to another type...
if (t != null) action(t); //still works
代わりに(悪いコード):
if (obj is T)
{
//bang, some other thread changes obj to another type...
action((T)obj); //InvalidCastException
}