機能的なF#。これはC#にゆっくり現れます。







何らかの理由で、この機能を使用しないことがよくあります。 まだ慣れていないのかもしれません そして、これがF#の機能であるという考えを持たずに使用することもあります。



その検討に進む前に、異なるバージョンの言語でさまざまな年に登場した最も興味深い機能についての小さな回顧展で、 ジャックを簡単に調べてみましょう。 言語の新しいバージョンがVisual Studioの新しいバージョンでリリースされるたびに注意してください。 一部の人にとっては、これは明らかかもしれませんが、数年にわたってC#で作業してきた開発者にとっても、これはニュースになるかもしれません(誰もがこれに注意を払うわけではありません)。



回顧

C#1.0 Visual Studio 2002

C#1.1 Visual Studio 2003-#line、pragma、xml docコメント

C#2.0 Visual Studio 2005- ジェネリック 、匿名メソッド、反復子/ yield、静的クラス

C#3.0 Visual Studio 2008- LINQ 、ラムダ式、暗黙的な型指定、拡張メソッド

C#4.0 Visual Studio 2010-動的なオプションのパラメーターと名前付き引数

C#5.0 Visual Studio 2012- async / await 、発信者情報、いくつかの重大な変更

C#6.0 Visual Studio 2015-ヌル条件演算子、文字列補間

C#7.0 Visual Studio 2017- タプル 、パターンマッチング、ローカル関数



一部の機能はめったに使用されませんが、何かが常に使用されます。 今でも、多くの場合、プロパティ名でOnPropertyChangedを使用していることがわかります。 つまり、OnPropertyChanged( "Price")のようなものです。 すでに言語の5番目のバージョンから、CallerMemberNameを使用して呼び出されたオブジェクトの名前を取得することが可能になりました。



public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChanged([CallerMemberName] string prop = "") { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop)); }
      
      





同じ方法でロギングを整理できます。 同じCallerMemberName属性は、呼び出し元のメソッドの名前を取得するのに役立ちます。 同様に、[CallerFilePath]と[CallerLineNumber]を使用してファイル名と行番号を取得できます。 ちなみに、これらの属性はF#で使用できますが、それらについては説明していません。



C#に登場した新機能について言えば、最近、言語の第6バージョン以降に始まったF#の「介入」に言及することをお忘れなく。 それはすべて、LINQを愛するすべての人から始まりました。 C#に登場した機能の一部を以下に示します。LINQ、免除、例外フィルター、自動プロパティ初期化子、式に基づいた関数メンバー、パターンマッチング、タプル

どうやら、近い将来にF#を学び始めなくても、すぐに関数型プログラミングは少し馴染みのあるものになるでしょう。 C#の「機能」機能のいくつかを見てみましょう。



免疫



これはオブジェクトの不変性に他なりません。 つまり、オブジェクトの値は作成後に変更できません。 F#では、すべての変数はデフォルトで不変です。 これをC#でどのように実装できますか? バージョン6以降、setを指定せずに読み取り専用プロパティを作成できます。 たとえば、次のように:



  public string Name { get;}
      
      





したがって、不変オブジェクトを快適に作成することが可能になります。



例外フィルター



これは、エラーを「キャッチ」して、キャプチャが機能するパラメーターを指定する機会です。 たとえば、次のように:



  try { SomeMethod(param); } catch (Exception e) when (param == null) { } catch (Exception e) { }
      
      





最初のブロックでは、param == nullの場合にのみエラーがキャッチされます。 2番目は、null以外のparam値で発生したエラーを取得します。



自動プロパティ初期化子



これは、アクセスメソッド(アクセサ)の直後にプロパティを初期化する機会です。 たとえば、次のように:



  public string AppUrl { get; set; } = "http://lalala.com";
      
      





または、値を返す別のメソッドに初期化を設定することもできます。



  public string AppUrl { get; set; } = InitializeProperty(); public static string InitializeProperty() { return "http://lalala.com "; }
      
      







表現型の関数メンバー



ラムダ式を使用してコードを短縮する便利な方法。 以前にこのように書かれたメソッド:



  public int Sum(int x, int y) { return x+y; } public string ServerIP { get { return "65.23.135.201"; } }
      
      





これでもっと短く書くことができます:



  public int Sum(int x, int y) => x+y; public string ServerIP => "65.23.135.201";
      
      





上記の機能はすべて、C#の6番目のバージョンに登場しました。

次に、言語の第7バージョンのF#から来たものを詳しく見てみましょう。



タプルまたはタプル



多くの人によると、この機能は重要性と使いやすさの点でLINQと比較できます。

彼はそれ自体で何を与えてくれますか。 まず、これは、クラスのインスタンスを作成せずにメソッドからいくつかの値を返す機能です。 メソッドに複数のパラメータを渡すことができますが、返せるのは1つだけだからです。 繰り返しになりますが、これまでの典型的な解決策は、クラスのインスタンスを作成することでした。 これでタプルを作成できます。

タプルの典型的な例:



  var unnamed = (35, "What is your age?");
      
      





ご覧のとおり、これは括弧で囲まれた2つの値を含む変数にすぎません。 この場合、タプルは名前なしと呼ばれ、値に名前付きのItemでアクセスできます。 たとえば、unnamed.Item1には35が含まれ、unnamed.Item2には「What is your age?」というテキストの行が含まれます。



タプルが匿名型に似ていることに気づいた場合、彼は正しいでしょう。 しかし、忘れてはならないニュアンスがあります。 匿名型は、メソッドのスコープ内でのみ使用できます。



名前付きタプルがあります。



  var named = (Answer: 35, Question: "What's your age again?");
      
      





名前付きタプルの変数には名前でアクセスできます。 この場合、named.Answerには35が格納され、named.Questionには質問のテキストを含む文字列が格納されます。

最も単純な例。 タプルの形式で値を返すメソッド:



  (int, string) GetXY() { int x = 1; string y = "One"; return (x, y); }
      
      





メソッドの戻り値はタプルで、その最初の値はint型の整数で、2番目の値は文字列です。

次のように変数の値を取得します。



  var xy = GetXY();
      
      





これで、xy.Item1とxy.Item2によってタプル要素にアクセスできます。



タプルには、分解などの興味深い機能があります。 これは、タプルから通常の変数を取得しています。 さて、またはタプルを個別の変数に分解すると言うことができます。 たとえば、リストと、このリストに関連するID-shnikを返すメソッドがあります。



  (int, List<string>) GetListWithId() { int x = 1; List<string> y = new List<string>(); return (x, y); }
      
      





タプルとしてではなく、変数の形ですぐに値を取得するには、次の2つの方法のいずれかを使用できます。



  (int x, List<string> y) = GetListWithId(); var (x, y) = GetXY();
      
      





C#バージョン7.1では、推測タプル名と呼ばれるオプションが導入されました。 次のように、おおよそロシア語に翻訳できます:タプルの名前の疑い。 これは、タプルの名前のない要素をItem1、Item2などだけでなく、タプルの作成に関与した変数の名前に基づいて形成された名前でも参照できることを意味します。 例:



  var tuple = (xa, y);
      
      





このタプルの要素には、tuple.aおよびtuple.yという名前でアクセスできます。



興味深いのは、この7.1の変更が互換性を破壊していることです。 それは後方互換性がありません。 しかし、C#7とC#7.1のリリース間のギャップは小さいため、導入することにしました。 要点です。 C#7で特定の方法で動作したコードの一部は、C#7.1で異なる動作をします。

この場合、実際のプロジェクトでそのようなコードを満たす機会は非常に少ないです。

例。 次のようなコードがあるとしましょう:



  int x=1; Action y = () => SomeMethod(); var tuple = (a: x, y); tuple.y();
      
      





最後の行に注意してください。これは明らかにSomeMethodと呼ばれるメソッドを呼び出します(そしてこのメ​​ソッドを呼び出しますが、C#7.1からのみ開始します)。

だからここに。 C#7.0では、SomeMethodは呼び出されませんが、yと呼ばれる拡張メソッドが呼び出されます。 これを言ってみましょう:



  public static class ExtClass { public static void y(this (int, Action) z) { // some code } }
      
      





タプルの拡張メソッドはまれであることに同意します。



4.7より前のバージョンの.NET Frameworkでプロジェクトを使用する場合、NuGetパッケージSystem.ValueTupleをインストールすることによってのみタプルを使用できます。 ただし、タプル構文の使用を開始する場合、Visual Studio 2017はこれを自分で通知する必要があります。 たぶんそれがタプルがまだそれほど頻繁に使用されない理由かもしれません。 Visual Studioの最新バージョンだけでなく、フレームワークの最新バージョンの1つでも動作する(またはNuGetパッケージをインストールする)必要があります。



パターンマッチング



このやや曖昧な名前の下には、驚くほどシンプルな機能が含まれています。

以前に使用されていて、もちろん現在使用できるコードの例を見てみましょう。



  if (someObject is Customer) { var c = (Customer)someObject; c.Balance = c.Balance + 1000; }
      
      





コードは完全に正常で、典型的で、よく使用されます。何か問題があるとは言えません。 ただし、これを少し減らす機会があります。



  if (someObject is Customer c) c.Balance = c.Balance + 1000;
      
      





someObjectがCustomerクラスに属している場合、Customer型の変数に変換されることがわかります。 この変数を使用すると、すぐに作業を開始できます。

パターンマッチングは、構文の砂糖であるだけでなく、開発者が他の言語で同様のデザインを処理してC#で使用できることも追加できます。

パターンマッチングは、ifだけでなく、Swithコンストラクトでも使用できます。 例:



  switch (userRole) { case Manager m: return m.Salary; case Partner p: return p.Income; }
      
      





with条件を使用して改良することもできます



  switch (userRole) { case Manager m with Salary<1500: return m.Salary*1.2; case Manager m: return m.Salary; case Partner p: return p.Income; }
      
      





この場合、最初のケースは、userRoleがマネージャーであり、その給与値が1500未満の場合にのみ実行されます。つまり、m.Salary <1500



C#8のイノベーションのリストには、最近Javaに登場した機能があります。 つまり、デフォルトのインターフェースメソッドです。 特に、この機能を使用すると、レガシーコードを変更できます。 たとえば、Java開発者自身がこの機能を使用してコレクションAPIを改善し、ラムダ式のサポートを追加できました。 たぶん、C#開発者はこの機能を使用してC#自体の何かを変更したいのでしょうか?



登場した類似点にもかかわらず、インターフェースは抽象クラスとはまったく異なります。 多重継承は、発生する多くの困難のために、C#で長い間放棄されてきました。 ただし、この場合、1つの方法のみを使用すれば、問題は少なくなります。 クラスが2つ以上のインターフェイスを継承し、複数のインターフェイスに同じ名前のメソッドがある場合、クラスはインターフェイスの名前でメソッド名を示す必要があります。 1つのメソッドのみを追跡する方が簡単です(特にIDEを使用する場合)。



C#言語は、非常に多くのさまざまなタイプのプロジェクトで使用されています。 人気の最初の行を占めていないという事実にもかかわらず、それはプロジェクトの種類の広さでユニークです。 Web開発、デスクトップ、クロスプラットフォーム、モバイル、ゲーム...関数型プログラミングのいくつかの機能や並行して開発している他のC#言語を含め、より汎用的になります。 別の言語からC#への切り替えが簡単になりました。 ただし、経験豊富なC#開発者は、他の言語の構文を理解しやすいことがわかります。



All Articles