マイクロチャンネル公共数:フィンテックオタク
金融情報技術企業で働くソフトウェア開発エンジニアの、CFAを通じて、知識や技術の共有がコンピュータや金融セクターを兼ね備えています。
Cの新機能#8.0
C#8.0は、時間の長い期間に開始されている、と結論されていない前に、同社は現在でもメインコンテンツビューとテストマイクロソフト公式ドキュメントバージョン6.0、プラスより個人的なものを使用した主な理由はします。https://ドキュメントを.microsoft.com / EN-US / DOTNET / CSHARP /いただきまし-新/ CSHARP-8
読み取り専用のメンバー(読み取り専用のメンバー)
構造体を表している構造体に加えて、読み取り専用のフロントでは、不変である、それはすべてのプロパティは読み取り専用である必要があります含まれています。読み取り専用のメンバーそれより正確に制御するので、そのプログラマは読み取り専用に設定されているメンバーを指定できることを意味します。以下のサンプルコードは、次のとおりです。
public struct ReadonlyMembers
{
public double X { get; set; }
public double Y { get; set; }
public double Z { get; set; }
public double Distance => Math.Sqrt(X * X + Y * Y + Z * Z);
public readonly override string ToString() => $"({X}, {Y},{Z}) is {Distance} from the origin";
public readonly void TestReadOnly()
{
//X = 10;//Complier error: Cannot assign to 'X' because it is read-only
}
}
ToStringメソッドとTestReadOnly:上記のコードフラグメントは、修飾された読み取り専用の二つの機能を備えます。あなたが割り当てXしようとするとTestReadOnlyでは、コンパイラはエラーメッセージのコメントを得られます。
さらに、ToStringメソッドがコンパイル距離警告:.非読み取り専用にCS8656のコールで使用されるの暗黙のコピーに「読み取り専用」メンバ結果からメンバー「ReadonlyMembers.Distance.get」「これは、」 コンパイラはしていませんので、 GETは状態を変更しないと思うのstruct、それは距離表示が読み取り専用に設定しなければなりませんが、あなたは自動的に属性にする必要はありません、コンパイラは、ToStringメソッドでアクセスX、Y、Zのメンバーので、状態を変更するためのアクセス権を取得していないと思いますこれは、コンパイラの警告が発生することはありません。
デフォルトのインターフェイスメソッド(デフォルトインタフェースメソッド)
以前のバージョンでは、インターフェースはそう一度ので、実装は、このインタフェースを変更する必要があります、そしてこの新機能は、新しいメンバーの追加が達成するために自分の時間を与えることができることができますことをすべての場所、インターフェイスに新しいメンバーを追加し、部分的に達成を含めることはできません何ら修正がインタフェースを実装するのに必要とされない場合ようにします。もう一つ注意すべきは、インタフェースの実装は種類を達成するために使用することはできませんので、使用のインターフェイスタイプに、インターフェース呼び出しを実装する場合、相続としてではなく、クラスの継承のようなインタフェースを実装しています。注:この機能はネットFramewok4.8、以下のコンパイラエラーではサポートされていない、と.NETのコア3.0でサポートされています。
ここではデフォルトのインターフェイスの例です。
public interface ICustomer
{
string Name { get; set; }
int OrderCount { get; set; }
public string GetOrderCount();
public string GetName()//default implemented method
{
return Name;
}
protected void PrintName()
{
Console.WriteLine("Name:" + Name ?? "");
}
private void DummyPrivateMethod()
{
Console.WriteLine("Name:" + Name ?? "");
}
}
public class FintechCustomer : ICustomer
{
public string Name { get; set; }
public int OrderCount { get; set; } = 100;
public string GetOrderCount()
{
return $"FintechCustomer order count:{OrderCount}";
}
public string GetName()//override default implemented method
{
return $"FintechCustomer Name:{Name}";
}
public FintechCustomer(string name) => Name = name;
}
public class NormalCustomer : ICustomer
{
public string Name { get; set; }
public int OrderCount { get; set; }
public string GetOrderCount()
{
return $"Normal customer order count:{OrderCount}";
}
public NormalCustomer(string name)
{
Name = name;
OrderCount = 0;
}
}
コードは2つの実装クラスおよびインタフェースICustomer FintechCustomer、NormalCustomerを含んでいます。ノートには、いくつかのポイントがあります。
- ICustomerインタフェースは、関連項目GetNameの具体的な実装を提供します
- FintechCustomer関連項目GetNameクラスは、それによって関連項目GetName ICustomerをカバーする、独自の実装を提供します
- NormalCustomerクラスは、独自のgetName達成していませんが、関連項目GetName ICustomer何の継承は、以下の例を通じて呼び出すこと、ありません、我々はこの点を確認することができます
- ICustomerインターフェース内では、メンバーは次のようなさまざまな修飾子を追加することができますなどプライベート、保護、公共、しかし、彼らは継承されません。
コードは次のような例は、呼び出します。
public class DefaultInterfaceImplementationUnitTest
{
[TestMethod]
public void FintechCustomer_TestGetName()
{
var name = "FintechCustomer1";
var fc = new FintechCustomer(name);
ICustomer ic = fc;
Assert.AreEqual($"FintechCustomer Name:{name}", fc.GetName());
Assert.AreEqual($"FintechCustomer Name:{name}", ic.GetName());
}
[TestMethod]
public void NormalCustomer_TestGetName()
{
var name = "NormalCustomer1";
var nc = new NormalCustomer(name);
ICustomer ic = nc;
//Assert.AreEqual(name, nc.GetName());//编译错误: Error CS1061 'NormalCustomer' does not contain a definition for 'GetName'...
Assert.AreEqual(name, ic.GetName());
}
}
NormalCustomer_TestGetName関数において、ラインは、関連項目GetName機能を実現ICustomerインターフェイスを呼び出すことができない実装クラスNormalCustomerへの参照を示しているがコメントアウトされ、そしてのみ関連項目GetName ICustomer参照によって呼び出すことができます。しかし、FintechCustomer_TestGetNameは、我々が見ることができるかどうかFintechCustomerの参照ICustomerは、関連項目GetName関数を呼び出すことができ、かつFintechCustomerの機能呼び出しです。
その他のパターンマッチング
C#7.0を導入型と定数と整合スイッチにより、C#8.0、その拡張を使用することです。これらのプロパティは、主にサポートデータに機能しているパラダイムをプログラミング分離し、データが別の関数やアルゴリズムがあるとき、実行時オブジェクトの種類に依存し、これらのプロパティを使用することを検討していない、彼らはの表現の代替設計を提供します道。我々は、スイッチ式とプロパティ、タプル、postition 3パターンマッチング後述します。
switch式(切り替え式)
例を見てください
public static RGBColor FromRainbow(Rainbow colorBand) =>
colorBand switch
{
Rainbow.Red => new RGBColor(0xFF, 0x00, 0x00),
Rainbow.Orange => new RGBColor(0xFF, 0x7F, 0x00),
Rainbow.Yellow => new RGBColor(0xFF, 0xFF, 0x00),
Rainbow.Green => new RGBColor(0x00, 0xFF, 0x00),
Rainbow.Blue => new RGBColor(0x00, 0x00, 0xFF),
Rainbow.Indigo => new RGBColor(0x4B, 0x00, 0x82),
Rainbow.Violet => new RGBColor(0x94, 0x00, 0xD3),
_ => throw new ArgumentException(message: "invalid enum value", paramName: nameof(colorBand)),
};
public enum Rainbow
{
Red,
Orange,
Yellow,
Green,
Blue,
Indigo,
Violet
}
FromRainbow上記の例から、我々は主に以下の4点で、switch文に比べてスイッチ式は大きな変化を遂げてきたことがわかります。
- 変数名(カラーバンド)スイッチキーワードの前面にあるので、コンパイラは簡単の文とswitch式を切り替えることが可能となります。
- =>置換および場合:各使用の一端とではなく、したがって、より簡単で直感的なこと。
- _デフォルト枝が置換されています。
- コードの一部は、表現ではなく、文です。
呼び出しがケースに一致しない場合は最後に、スイッチ式は、値を返すか、例外をスローする必要があり、例外がはInvalidOperationにスローされます、警告が与えられたときにも、すべてのケースが含まれていないブランチを切り替えますコンパイラ。
属性パターン(プロパティのパターン)
次の例では、からの話です
public static decimal ComputeSalesTax(Address location, decimal salePrice) =>
location switch
{
{ State: "WA" } => salePrice * 0.06M,
{ State: "MN" } => salePrice * 0.75M,
{ State: "MI" } => salePrice * 0.05M,
// other cases removed for brevity...
_ => 0M
};
public class Address
{
public string State { get; set; }
}
上記のコードは、スイッチ式の内部にマッチ、スイッチ機能ComputeSalesTax式を使用して属性パターンを使用します。以下に例を示し:「WA」のState属性値の場所ならば、それはsalePrice * 0.06Mを返します。
{ State: "WA" } => salePrice * 0.06M,
タプルパターン(タプルパターン)
いくつかのアルゴリズムは、複数の入力を必要とする、モデルが表現複数の値を一致させるために使用されるタプルスイッチにおけるタプルは、以下が例であることができ:
public static string RockPaperScissors(string first, string second)
=> (first, second) switch
{
("rock", "paper") => "rock is covered by paper. Paper wins.",
("rock", "scissors") => "rock breaks scissors. Rock wins.",
("paper", "rock") => "paper covers rock. Paper wins.",
("paper", "scissors") => "paper is cut by scissors. Scissors wins.",
("scissors", "rock") => "scissors is broken by rock. Rock wins.",
("scissors", "paper") => "scissors cuts paper. Scissors wins.",
(_, _) => "tie"
};
上記ロック紙はさみゲーム、スイッチ式は、マッチングタプルを使用して見ることができるだけそのメッセージ、前記(戻りもあり、)=>「TIE」を、一致するものが見つからない「タイ」に戻ったことを示します。
位置モード(位置パターン)
クラスDeconstrut機能がある場合、C#7.0が導入解体機能は、それが直接の変数のクラスの異なる特性に分解することができます。C#8.0でポジションスイッチ発現パターンによって複数の属性に一致させることができ、以下は一例です。
public static Quadrant GetQuadrant(Point point) => point switch
{
(0, 0) => Quadrant.Origin,
var (x, y) when x > 0 && y > 0 => Quadrant.One,
var (x, y) when x < 0 && y > 0 => Quadrant.Two,
var (x, y) when x < 0 && y < 0 => Quadrant.Three,
var (x, y) when x > 0 && y < 0 => Quadrant.Four,
var (_, _) => Quadrant.OnBorder,
_ => Quadrant.Unknown
};
public class Point
{
public int X { get; }
public int Y { get; }
public Point(int x, int y) => (X, Y) = (x, y);
public void Deconstruct(out int x, out int y) =>
(x, y) = (X, Y);
}
この例では、Pointクラスは、X、Yは、別個の変数に分解することができるよう、解体関数を含みます。GetQuadrant機能において、オブジェクトは解体二つの変数の関数で、点X、Yに分解され、分岐条件が成立しているか否かで判断します。
ステートメントを使用して
以前のバージョンでは、我々はライフサイクルの終わりにIDisposableをオブジェクトの実現を確実にするために使用してステートメントを使用することができ、そのDisposeメソッドが呼び出されます。C#8.0では、我々はよりコンパクトな声明やコードを使用して同じことを行います。ここでは、開いているファイルの例です。
static int WriteLinesToFile(IEnumerable<string> lines)
{
using var file = new System.IO.StreamWriter("WriteLines2.txt");
// Notice how we declare skippedLines after the using statement.
int skippedLines = 0;
foreach (string line in lines)
{
if (!line.Contains("Second"))
{
file.WriteLine(line);
}
else
{
skippedLines++;
}
}
// Notice how skippedLines is in scope here.
return skippedLines;
// file is disposed here
}
上記の例では、関数呼び出しが戻るとき、ファイルオブジェクトは自動的に廃棄方法は、宣言されたオブジェクトを使用するIDisposableインターを実装していない場合、コンパイラはエラーメッセージを生成呼びます。
静的ローカル関数(静的ローカル関数)
あなたはそのローカル変数の外に捕獲されたローカル関数を訪問したくない場合は、我々は静的な制限を追加することができ、以下は一例です:
public int Add(int x, int y)
{
return x + y;
int GetX()
{
return x;
}
static int GetY()
{
return y;//Compiler error:A static local function cannot contain a reference to 'y'
}
}
上記の例では、機能を追加するのgetYが静的である2つのローカル機能を含んで、それはローカル変数周辺Yを指すので、コンパイルエラーにコメントが存在することになります。
使い捨てREFの構造体
それはの処分することはできませんので、REFの構造は、もちろんIDisposableをは仕事をしない、任意のインタフェースを実装していないため。C#8.0では、限り、それはアクセスボイド廃棄()関数を有するように、それは廃棄することができ、例としては、次の通りであります:
ref struct DisposableRefStruct
{
public void Dispose()
{
Console.WriteLine("ref struct dispose method is called");
}
}
public class DisposableRefStructTester
{
public static void Test()
{
using (var s = new DisposableRefStruct())
{
Console.WriteLine("Test Disposable Ref Struct");
}
}
IDisposableをインターフェイスを実装しますが、空のDispose()メソッドではない例DisposableRefStructからわかるように、それは言葉と文を使用しても可能です。また、この機能は利用可能読み取り専用refの構造体であります
ヌル参照型であってもよい(NULL可能参照型)
null参照の型チェックすることができ、プロジェクトファイルに以下の設定を追加することによってオンにすることができます。開封後は、コンパイラは、nullがタイプに加えた後、前と同じタイプでなければならないよう、すべての参照型がnull値を割り当てられていないことだと思いますか?参照タイプを表すためには、空とすることができます。詳細については、参照してください。
https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references
https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/nullable-reference-種類
https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/upgrade-to-nullable-references
<Nullable>enable</Nullable>
非同期フロー(非同期ストリーム)
同期に対応する機能のIEnumerable
非同期バージョンは、非同期ストリーム機能は、以下の3つの機能を備えています。
- 使用非同期で修正します
- 戻り値の型は次のとおりです。IAsyncEnumerable
- この関数は利回りリターン列挙子パラダイムを実装するためのステートメントが含まれています
次に例を示します。
public static async IAsyncEnumerable<int> GenerateSequence()
{
for (int i = 0; i < 20; i++)
{
await Task.Delay(100);
yield return i;
}
}
public static async Task ConsumeAsyncStream()
{
await foreach (var i in GenerateSequence())
{
Console.WriteLine(i);
}
}
戻り値は、本実施形態GenerateSequence ConsumeAsyncStream非同期ストリームは、前面のawaitのforeachを添加することによって非同期ストリームを列挙します。
インデックスと範囲(インデックスと範囲)
そして、単一の要素またはシーケンスの範囲にアクセスするためのインデックスの範囲は、単純な構文を提供します。ビットのPythonのスライスのようにこの概念が、構文は多少異なります。実装されているこの機能は、次の2つの新しいタイプの2つの新しい事業者によって異なります。
- System.Index、シーケンスインデックスを表し、
- ^演算子は、インデックスが戻ってから開始された意味します
- System.Rangeのサブシーケンスを表します
...オペレータの範囲の始まりと終わりを示します
次のようにいくつかのコード例は以下のとおりです。
public class IndicesAndRanges
{
public string[] words = new string[]
{
// index from start index from end
"The", // 0 ^9
"quick", // 1 ^8
"brown", // 2 ^7
"fox", // 3 ^6
"jumped", // 4 ^5
"over", // 5 ^4
"the", // 6 ^3
"lazy", // 7 ^2
"dog" // 8 ^1
}; // 9 (or words.Length) ^0
public void Test()
{
Console.WriteLine($"The last word is {words[^1]}"); // writes "dog"
var quickBrownFox = words[1..4];// "quick", "brown", and "fox"
var lazyDog = words[^2..^0];//"lazy" and "dog"
var allWords = words[..]; // contains "The" through "dog".
var firstPhrase = words[..4]; // contains "The" through "fox"
var lastPhrase = words[6..]; // contains "the", "lazy" and "dog"
Range phrase = 1..4;//Range phrase = 1..4;
var text = words[phrase];
}
}
ヌル合併の割り当て
C#8.0を導入ヌル= ??合わせ代入演算子。左のオペランドがNULLの場合にのみ、右のオペランドの値を左のオペランドに割り当てられました。例としては、次のとおりです:
List<int> numbers = null;
int? i = null;
numbers ??= new List<int>();
numbers.Add(i ??= 17);
numbers.Add(i ??= 20);
Console.WriteLine(string.Join(" ", numbers)); // output: 17 17
Console.WriteLine(i); // output: 17
アンマネージド構築のタイプ
以前に、タイプ(パラメータの少なくとも1種を含むタイプ)の構成は、アンマネージタイプにすることはできません。C#8.0から始めて、唯一の非管理型のフィールドを含む構造の型の値ならば、種類は、次の例を管理されていません。
public struct Coords<T>
{
public T X;
public T Y;
}
これは、アンマネージおよび他のタイプで作成することができ、または型スタックに割り当てられたメモリブロックへのポインタ。
ネストされた式のstackalloc
C#8.0、式の結果は、型stackallocのSystem.Spanある場合
またはSystem.ReadOnlySpan 、表現stackalloc他の式で使用することができ、次のように具体的な例であります:
Span<int> numbers = stackalloc[] { 1, 2, 3, 4, 5, 6 };
var ind = numbers.IndexOfAny(stackalloc[] { 2, 4, 6 ,8 });
Console.WriteLine(ind); // output: 1
文字列の補間強化
文字列$とマーク@どこにでも配置することができるの順で補間:$ @「...」と$は、@「...」正しいですが、C#の以前のバージョンでは、$マークは@記号の前に現れなければなりません。