[解決済み] このスイッチ/パターンマッチングの考え方にメリットはあるのでしょうか?
質問
最近、F#を見ていて、すぐにフェンスを飛び越えることはないだろうが、C#(またはライブラリサポート)が生活をより簡単にすることができるいくつかの領域を明らかにした。
特に、F#のパターンマッチ機能について考えているのですが、非常に豊富な構文が可能で、現在のswitchやconditionalのC#の同等品よりもはるかに表現力が豊かです。F#のパターンマッチは、現在のC#のswitchやconditionよりもはるかに表現力が豊かです。
- 型によるマッチング (判別されたユニオンのフルカバレッジチェックを含む) [これはバインドされた変数の型も推測し、メンバアクセスなどを与えることに注意] 。
- 述語によるマッチング
- 上記の組み合わせ(および私が知らない他のシナリオもあるかもしれません)
C#が最終的にこの豊富な機能の一部を利用するのは素晴らしいことですが、その間、私は実行時に何ができるかを調べてきました - たとえば、いくつかのオブジェクトを組み合わせて許可するのはかなり簡単です。
var getRentPrice = new Switch<Vehicle, int>()
.Case<Motorcycle>(bike => 100 + bike.Cylinders * 10) // "bike" here is typed as Motorcycle
.Case<Bicycle>(30) // returns a constant
.Case<Car>(car => car.EngineType == EngineType.Diesel, car => 220 + car.Doors * 20)
.Case<Car>(car => car.EngineType == EngineType.Gasoline, car => 200 + car.Doors * 20)
.ElseThrow(); // or could use a Default(...) terminator
ここで、getRentPriceはFunc<Vehicle,int>です。
[注意 - たぶん、ここでのSwitch/Caseは間違った用語だと思いますが...アイデアを示しています]。
この方法は、if/elseを繰り返したり、複合三項条件式(三項以外の式では括弧が多くなり、非常に煩雑になる)を使うよりもずっと分かりやすいと私は思います。また ロット 例えば、VB の Select...Case "x To y" のような InRange(...) マッチのような、より特殊なマッチへの簡単な拡張が可能です。
私は、上記のような構成が(言語サポートがない場合)あまり利点があると人々が考えているかどうかを測ろうとしているのです。
なお、私は上記の3つのバリエーションで遊んでいます。
- Func<TSource,TValue> 評価用バージョン - 複合三項条件文に匹敵するもの
- Action<TSource> バージョン - if/else if/else if/else に相当するものです。
- Expression<Func<TSource,TValue>> バージョン - 最初のバージョンと同様ですが、任意の LINQ プロバイダで使用可能です。
さらに、Expressionベースのバージョンを使用すると、Expressionツリーの書き換えが可能になり、繰り返し呼び出すのではなく、すべての分岐を単一の複合条件Expressionにインライン化することができます。最近確認したわけではありませんが、初期のEntity Frameworkのビルドでは、InvocationExpressionがあまり好きではなかったので、これが必要だったように記憶しています。また、LINQ-to-Objectsでは、デリゲートの繰り返し呼び出しを避けるため、より効率的に使用できます。テストでは、上記のようなマッチ(Expressionフォームを使用)は、同等のC#複合条件文と比較して同じ速度(実際には、わずかにより速い)で実行されることを示しています。ただし、Func<...> に基づくバージョンでは、C# の条件文の 4 倍の時間がかかりますが、それでも非常に速く、ほとんどのユースケースで大きなボトルネックになることはないでしょう。
上記について(あるいは C# 言語サポートの充実の可能性について)、ご意見・ご感想・批評などありましたら、ぜひお聞かせください。
どのように解決するのか?
C# 7では、できます。
switch(shape)
{
case Circle c:
WriteLine($"circle with radius {c.Radius}");
break;
case Rectangle s when (s.Length == s.Height):
WriteLine($"{s.Length} x {s.Height} square");
break;
case Rectangle r:
WriteLine($"{r.Length} x {r.Height} rectangle");
break;
default:
WriteLine("<unknown shape>");
break;
case null:
throw new ArgumentNullException(nameof(shape));
}
関連
-
[解決済み] このコマンドに関連する開いているDataReaderがすでにあり、最初にそれを閉じる必要があります。
-
[解決済み】スクリプトクラスが見つからないので、スクリプトコンポーネントを追加できない?
-
[解決済み】値が期待した範囲に収まらない
-
[解決済み】MetadataException: 指定されたメタデータ・リソースをロードできない
-
[解決済み】インデックスが範囲外でした。コレクションパラメータname:indexのサイズより小さく、非負でなければなりません。
-
[解決済み] スイッチオンタイプ」これ以上の代案はないのでしょうか?
-
[解決済み】FluentとQuery Expression - どちらか一方にメリットがあるのでしょうか?
-
[解決済み】C#でif/elseとswitch-caseを使うことに大きな違いはあるのでしょうか?
-
[解決済み】JavaScriptの文字列マッチングのためのSwitch文
-
[解決済み] C# 8 switch 式で、複数のケースで同じ結果を得ることができる
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】MetadataException: 指定されたメタデータ・リソースをロードできない
-
[解決済み】Swashbuckle/Swagger + ASP.Net Core: "Failed to load API definition" (API定義の読み込みに失敗しました
-
[解決済み】C#のequal to演算子でtextとvarcharのデータ型は互換性がない
-
[解決済み】aspNetCore 2.2.0 - AspNetCoreModuleV2 エラー
-
[解決済み】エラー「必要なフォーマルパラメータに対応する引数が与えられていない」を解決する?
-
[解決済み】ファイルやアセンブリ、またはその依存関係の1つをロードできませんでした。
-
[解決済み】プロセスが実行されているかどうかを知るには?
-
[解決済み】別のスレッドがこのオブジェクトを所有しているため、呼び出し側のスレッドはこのオブジェクトにアクセスできない
-
[解決済み] スイッチオンタイプ」これ以上の代案はないのでしょうか?
-
[解決済み】C#のスイッチオンタイプ【重複あり