C#の新しいバージョンの他の機能を見てみましょう。 だから! さあ始めましょう!
アウト変数
現在、C#では、 outパラメーターの使用は 、私たちが望むほど柔軟ではありません。 outパラメータを使用してメソッドを呼び出す前に、まずメソッドに渡す変数を宣言する必要があります。 通常、これらの変数は初期化されないため(メソッドによって書き換えられるため)、 varを使用して変数を宣言することはできません。したがって、完全な型を指定する必要があります。
public void PrintCoordinates(Point p) { int x, y; // have to "predeclare" p.GetCoordinates(out x, out y); WriteLine($"({x}, {y})"); }
C#7では、 out変数が導入されています。 これらを使用すると、変数をout引数として渡す場所で変数を宣言できます。
public void PrintCoordinates(Point p) { p.GetCoordinates(out int x, out int y); WriteLine($"({x}, {y})"); }
変数は閉じているブロックの外側のスコープに移動するため、次の行で使用できることに注意してください。
out変数はoutパラメーターの引数として直接宣言されているため、コンパイラーは(競合するオーバーロードがない場合)型を推測できるため、宣言時に型の代わりにvarを使用できます。
p.GetCoordinates(out var x, out var y);
通常、 出力パラメータはTry ...テンプレートで使用され、論理的な戻り値は成功を示し、 出力パラメータは結果を保持します。
public void PrintStars(string s) { if (int.TryParse(s, out var i)) { WriteLine(new string('*', i)); } else { WriteLine("Cloudy - no stars tonight!"); } }
_の形式の出力パラメーターで「 ワイルドカード 」を使用して、不要な出力パラメーターを無視することもできます。
p.GetCoordinates(out int x, out _); // I only care about x
ワイルドカードを使用して型宣言を省略することができることに注意してください。
string inputDate = ""; if (DateTime.TryParse(inputDate, out DateTime dt)) { // dt }
問題は、文字列をDateTime型の変数に変換できなかった場合、出力値を使用しようとする場合です。
変数にはデフォルト値があります 。
リテラルの機能強化
C#7では、数値リテラル内の数字の区切り文字として「 _ 」文字を使用できます。
var d = 123_456; var x = 0xAB_CD_EF;
この文字は、読みやすさを向上させるために、必要な回数だけ数字の間のどこにでも配置できます。 値には影響しません。
区切り文字は、 byte 、 int 、 long 、 decimal 、 float 、およびdouble型とともに使用できます。
public const long BillionsAndBillions = 100_000_000_000; public const double AvogadroConstant = 6.022_140_857_747_474e23; public const decimal GoldenRatio = 1.618_033_988_749_894_848_204_586_834_365_638_117_720_309_179M;
さらに、C#7はバイナリリテラルを提供します 。 これで、バイナリ形式で数値を書くことができます。
var b = 0b101010111100110111101111;
定数の先頭の0bは、数値がバイナリ形式で書き込まれることを意味します。
小数点区切り文字を使用することもできます。これにより、リテラルの可読性が確実に向上します。
var b = 0b1010_1011_1100_1101_1110_1111;
放電区切り文字は、リテラルの末尾または先頭に立つことはできません
byte a = 0b_0000_0001; //INVALID: Digit separator cannot be at the start or end of the value byte b = 0b1_0000_0001; //INVALID: 257 doesn't fit in a byte byte c = 0b0_0000_0001; //VALID: 1 fits into a byte just fine
Refの戻り値とローカル
( ref修飾子を使用して)参照によってメソッドパラメーターを渡すことができるように、参照によってそれらを返すことも、ローカル変数に参照によって保存することもできるようになりました。
public ref int Find(int number, int[] numbers) { for (int i = 0; i < numbers.Length; i++) { if (numbers[i] == number) { return ref numbers[i]; // return the storage location, not the value } } throw new IndexOutOfRangeException($"{nameof(number)} not found"); } int[] array = { 1, 15, -39, 0, 7, 14, -12 }; ref int place = ref Find(7, array); // aliases 7's place in the array place = 9; // replaces 7 with 9 in the array WriteLine(array[4]); // prints 9
これは、大きなデータ構造から特定のフィールドを返す場合に便利です。 たとえば、ゲームには、事前に分散された構造の大きな配列にデータが含まれている場合があります(ガベージコレクションの一時停止を避けるため)。 現在、メソッドは、呼び出し元のメソッドが読み取りおよび変更できる構造体へのリンクを直接返すことができます。
いくつかのセキュリティ制限があります。
- あなたは「安全に返す」リンクのみを返すことができます:あなたに渡されたリンクとオブジェクトのフィールドを指すリンクのみ
- ローカルref変数は特定の保存場所で初期化され、別の場所を指すように変更することはできません
非同期メソッドで返されるジェネリック型
これまでのところ、C#の非同期メソッドはvoid 、 Task、またはTask ‹T›を返す必要があります。 C#7では、非同期メソッドから返されるように他の型を定義できます。 戻り値の型は非同期パターンと一致する必要があります。つまり、 GetAwaiterメソッドが使用可能でなければなりません。 ケーススタディ:.NET Frameworkは、この新しい言語機能を使用する新しいValueTask型を追加します
TaskおよびTask ‹T›は参照型であるため、パフォーマンスに影響するセグメントにメモリを割り当てると(特に限られたサイクルでメモリを割り当てる場合)、パフォーマンスが大幅に低下する可能性があります。 汎用戻り型のサポートにより、参照型の代わりに意味のある小さな型を返すことができます。これにより、メモリの過剰割り当てを防ぐことができます。
class Program { static Random rnd; static void Main() { Console.WriteLine($"You rolled {GetDiceRoll().Result}"); } private static async ValueTask GetDiceRoll() { Console.WriteLine("...Shaking the dice..."); int roll1 = await Roll(); int roll2 = await Roll(); return roll1 + roll2; } private static async ValueTask Roll() { if (rnd == null) rnd = new Random(); await Task.Delay(500); int diceRoll = rnd.Next(1, 7); return diceRoll; } }
おわりに
開発を容易にし、時間を節約し、コードを読みやすくするため、C#言語の新機能を使用します。 この記事では、C#7バージョンに関する一連の記事を終了します。 興味のある質問は、コメントまたはPMでお願いします。 答えます。 みんなありがとう!