.Net(VB C#) LINQ
Enumerable.Single メソッド、SingleOrDefaultメソッド

Enumerable.Singleメソッド
【C#】
シーケンスの唯一の要素を返します。シーケンス内の要素が 1 つだけではない場合は、例外をスローします。
public static TSource Single<TSource>
    (this IEnumerable<TSource> source)
    
指定された条件を満たす、シーケンスの唯一の要素を返します。そのような要素が複数存在する場合は、例外をスローします。
public static TSource Single<TSource>
    (this IEnumerable source, Func predicate)
【VB】
シーケンスの唯一の要素を返します。シーケンス内の要素が 1 つだけではない場合は、例外をスローします。
<ExtensionAttribute>
Public Shared Function Single(Of TSource) 
    (source As IEnumerable(Of TSource)) 
    As TSource

指定された条件を満たす、シーケンスの唯一の要素を返します。そのような要素が複数存在する場合は、例外をスローします。
<ExtensionAttribute>
Public Shared Function Single(Of TSource) 
    (source As IEnumerable(Of TSource), predicate As Func(Of TSource, Boolean)) 
    As TSource

Enumerable.SingleOrDefaultメソッド
【C#】
シーケンスの唯一の要素を返します。シーケンスが空の場合、既定値を返します。
シーケンス内に要素が複数ある場合、このメソッドは例外をスローします。
public static TSource SingleOrDefault<TSource>
    (this IEnumerable<TSource> source) 
    
指定された条件を満たす、シーケンスの唯一の要素を返します。そのような要素が存在しない場合、既定値を返します。
複数の要素が条件を満たす場合、このメソッドは例外をスローします。
public static TSource SingleOrDefault<TSource>
    (this IEnumerable<TSource> source, Func<TSource, bool> predicate) 
【VB】
シーケンスの唯一の要素を返します。シーケンスが空の場合、既定値を返します。
シーケンス内に要素が複数ある場合、このメソッドは例外をスローします。
<ExtensionAttribute>
Public Shared Function SingleOrDefault(Of TSource) 
    (source As IEnumerable(Of TSource)) 
    As TSource
    
指定された条件を満たす、シーケンスの唯一の要素を返します。そのような要素が存在しない場合、既定値を返します。
複数の要素が条件を満たす場合、このメソッドは例外をスローします。
<ExtensionAttribute>
Public Shared Function SingleOrDefault(Of TSource) 
    (source As IEnumerable(Of TSource), predicate As Func(Of TSource, Boolean)) As TSource

シーケンス(配列やコレクションなど)の要素が一つだけのとき、その唯一の要素を取得するメソッドです。
Singleメソッドはシーケンスの要素が一つではないとき(つまりシーケンスの要素が0件または複数件ある状態)例外をスローします。
SingleOrDefaultメソッドはシーケンスの要素が0件のときは、デフォルト値(値型なら初期値、参照型ならnull)を返します。シーケンスの要素が複数のときは、例外をスローします。

このメソッドは即時実行されます。


SingleメソッドとFirstメソッドの使い分けについて
Firstメソッドでも1件の要素を取得することができます。
Firstメソッドは複数要素のシーケンスから、一番最初の要素を取得します。
要素が一つのシーケンスから一番最初の要素を取得すれば、唯一の要素を取得するSingleメソッドと同じ結果にはなります。
しかし後に保守する読み手には「シーケンスの要素は複数件の可能性がある」と読み取れます。
たとえFirstメソッドを使用した結果が同じであっても、シーケンスの要素が必ず1件であるということが明確なときには、Singleメソッドを使用します。
後に保守する読み手に余計な誤解を与えず「シーケンスの要素は1件だけ」ということが明確になります。


テスト用の果物クラスです。
【C#】
private class Fruit
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string Rank { get; set; }
    public decimal Price { get; set; }
}
【VB】
Private Class Fruit
    Public Property ID As Integer
    Public Property Name As String
    Public Property Rank As String
    Public Property Price As Decimal
End Class
まずはFirsメソッド、FirstOrDefaultメソッドを使用して、唯一の要素を取得します。
リストの要素が1件なので、どちらも問題なく取得できます。
【C#】
//テストデータ
var fruits = new List<Fruit>()
                {
                    new Fruit(){ID = 1, Name = "りんご", Rank = "A" , Price = 1000 }
                };


//Singleメソッドを使用して唯一の要素を取得
Fruit fruit1 = fruits.Single();
//出力  
Console.WriteLine("ID={0}, 名称={1}", fruit1.ID, fruit1.Name);
//ID=1, 名称=りんご


//SingleOrDefaultメソッドを使用して唯一の要素を取得
Fruit fruit2 = fruits.SingleOrDefault();
//出力  
Console.WriteLine("ID={0}, 名称={1}", fruit2.ID, fruit2.Name);
//ID=1, 名称=りんご
【VB】
'テストデータ
Dim fruits = New List(Of Fruit)() From
    {
        New Fruit() With {.ID = 1, .Name = "りんご", .Rank = "A", .Price = 1000}
    }

'Singleメソッドを使用して唯一の要素を取得
Dim fruit1 As Fruit = fruits.Single()
'出力  
Console.WriteLine("ID={0}, 名称={1}", fruit1.ID, fruit1.Name)
'ID=1, 名称=りんご


'SingleOrDefaultメソッドを使用して唯一の要素を取得
Dim fruit2 As Fruit = fruits.SingleOrDefault()
'出力  
Console.WriteLine("ID={0}, 名称={1}", fruit2.ID, fruit2.Name)
'ID=1, 名称=りんご
次にリストの要素を複数にしてみます。
Singleメソッド、SingleOrDefaultメソッドともにInvalidOperationException例外がスローされます。
【C#】
//テストデータ
var fruits = new List<Fruit>()
                {
                    new Fruit(){ID = 1, Name = "りんご", Rank = "A" , Price = 1000 },
                    new Fruit(){ID = 2, Name = "みかん", Rank = "A" , Price = 600 }
                };


//Singleメソッドを使用して唯一の要素を取得
//例外InvalidOperationExceptionがスローされる 
Fruit fruit1 = fruits.Single();


//SingleOrDefaultメソッドを使用して唯一の要素を取得
//例外InvalidOperationExceptionがスローされる 
Fruit fruit2 = fruits.SingleOrDefault();
【VB】
'テストデータ
Dim fruits = New List(Of Fruit)() From
    {
        New Fruit() With {.ID = 1, .Name = "りんご", .Rank = "A", .Price = 1000},
        New Fruit() With {.ID = 2, .Name = "みかん", .Rank = "A", .Price = 600}
}

'Singleメソッドを使用して唯一の要素を取得
'例外InvalidOperationExceptionがスローされる 
Dim fruit1 As Fruit = fruits.Single()


'Singleメソッドを使用して唯一の要素を取得
'例外InvalidOperationExceptionがスローされる 
Dim fruit2 As Fruit = fruits.SingleOrDefault()
次はリストの要素を0件にしてみます。
SingleメソッドはInvalidOperationException例外がスローされますが
SingleOrDefaultメソッドでは、参照型の規定値であるnullが返ります。
【C#】
//テストデータ
var fruits = new List<Fruit>();


//Singleメソッドを使用して唯一の要素を取得
//例外InvalidOperationExceptionがスローされる 
Fruit fruit1 = fruits.Single();


//SingleOrDefaultメソッドを使用して唯一の要素を取得
//参照型なのでnullが返る   
Fruit fruit2 = fruits.SingleOrDefault();
//出力  
Console.WriteLine(fruit2 == null ? "null" : fruit2.Name);  
//null 
【VB】
'テストデータ
Dim fruits = New List(Of Fruit)()

'Singleメソッドを使用して唯一の要素を取得
'例外InvalidOperationExceptionがスローされる 
Dim fruit1 As Fruit = fruits.Single()


'SingleOrDefaultメソッドを使用して唯一の要素を取得
'参照型なのでnullが返る   
Dim fruit2 As Fruit = fruits.SingleOrDefault()
'出力  
Console.WriteLine(If(fruit2 Is Nothing, "nothing", fruit2.Name))
'nothing 

Singleメソッド、SingleOrDefaultメソッドには、抽出条件を指定できるオーバーロードメソッドがあります。
条件に該当するデータが1件(または0件)となるような抽出条件を指定します。
抽出条件に該当するデータが複数件の場合、Singleメソッド、SingleOrDefaultメソッドともに例外をスローします。
抽出条件に該当するデータが0件の場合、Singleメソッドは例外をスローし、SingleOrDefaultメソッドは規定値を返します。
【C#】
//テストデータ
var fruits = new List<Fruit>()  
    {  
        new Fruit(){ID = 1, Name = "りんご", Rank = "A" , Price = 1000 },  
        new Fruit(){ID = 2, Name = "みかん", Rank = "A" , Price = 600 },  
        new Fruit(){ID = 3, Name = "ぶどう", Rank = "B" , Price = 1200 },  
        new Fruit(){ID = 4, Name = "りんご", Rank = "B" , Price = 800 },  
        new Fruit(){ID = 5, Name = "みかん", Rank = "A" , Price = 500 }  
    };  

//Singleメソッドを使用して唯一の要素を取得
Fruit fruit1 = fruits.Single(itm => itm.ID == 3);
//出力
Console.WriteLine("ID={0}, 名称={1}", fruit1.ID, fruit1.Name);
//ID=3, 名称=ぶどう

//SingleOrDefaultメソッドを使用して唯一の要素を取得
Fruit fruit2 = fruits.SingleOrDefault(itm => itm.ID == 3);
//出力
Console.WriteLine("ID={0}, 名称={1}", fruit2.ID, fruit2.Name);
//ID=3, 名称=ぶどう
【VB】
'テストデータ
Dim fruits As New List(Of Fruit)() From
    {
        New Fruit() With {.ID = 1, .Name = "りんご", .Rank = "A", .Price = 1000},
        New Fruit() With {.ID = 2, .Name = "みかん", .Rank = "A", .Price = 600},
        New Fruit() With {.ID = 3, .Name = "ぶどう", .Rank = "B", .Price = 1200},
        New Fruit() With {.ID = 4, .Name = "りんご", .Rank = "B", .Price = 800},
        New Fruit() With {.ID = 5, .Name = "みかん", .Rank = "A", .Price = 500}
    }

'Singleメソッドを使用して唯一の要素を取得
Dim fruit1 As Fruit = fruits.Single(Function(itm) itm.ID = 3)
'出力
Console.WriteLine("ID={0}, 名称={1}", fruit1.ID, fruit1.Name)
'ID=3, 名称=ぶどう

'SingleOrDefaultメソッドを使用して唯一の要素を取得
Dim fruit2 As Fruit = fruits.SingleOrDefault(Function(itm) itm.ID = 3)
'出力
Console.WriteLine("ID={0}, 名称={1}", fruit2.ID, fruit2.Name)
'ID=3, 名称=ぶどう
※VBの場合、コンパイルオプションで「Option Infer」をONにし、型推論を有効にしてください。

.Net(VB C#) LINQのメソッド一覧

0 件のコメント: