2016-02-12T00:02:47の更新内容

programming/netfx/arrays/0_abstract/index.wiki.txt

current previous
4,9 4,9
 

        

        
 
#navi(..)
#navi(..)
 

        

        
~
配列(''array'')とは同じデータ型の要素が集まったデータ構造で、固定長の''集合''、''ベクトル''です。 ここでは配列の宣言・作成方法と、配列を使った基本的な操作について見ていきます。 配列内にある要素の検索や、配列のリサイズといった操作については[[programming/netfx/arrays/2_operations]]で解説します。
配列とは同じデータ型の要素が集まったデータ構造で、固定長の集合・ベクトルです。 ここでは配列の宣言・作成方法と、配列を使った基本的な操作について見ていきます。 要素の検索やリサイズなどの操作については[[programming/netfx/arrays/2_operations]]で解説します。
 

        

        
~
なお、ここでは次元のない配列(1次元配列)のみを扱います。 多次元配列については[[programming/netfx/arrays/1_multidimensional]]で個別に解説します。 また可変長のデータ構造として[[リスト>programming/netfx/collections/2_generic_1_list]]などの[[コレクション>programming/netfx/collections]]なども存在しますが、ここでは扱いません。
なお、ここでは次元のない配列(1次元配列)のみを扱います。 多次元配列については[[programming/netfx/arrays/1_multidimensional]]で追って解説します。 また可変長のデータ構造として[[リスト>programming/netfx/collections/2_generic_1_list]]などの[[コレクション>programming/netfx/collections]]なども存在しますが、ここでは扱いません。
 

        

        
 
#relevantdocs
#relevantdocs
 

        

        
21,74 21,10
 

        

        
 
#adunit
#adunit
 

        

        
+
*配列とは
+
プログラム要素として見た場合の''配列''とは、複数の同じ種類(=同じ''型'')の値に名前を与えてひとまとめにして扱うものです。 複数の変数の場合は個々の値にそれぞれ名前が与えられますが、配列では値の集まりにひとつの名前(=配列の変数名)が与えられ、配列内の個々の値(''要素'')は''インデックス''によって区別します(インデックスは''添え字''とも呼ばれる)。
+

          
+
#tabpage(codelang=cs,container-title=複数の変数と配列)
+
#code{{
+
using System;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // 複数の変数
+
    string user0 = "Alice";
+
    string user1 = "Bob";
+
    string user2 = "Charlie";
+

          
+
    // 配列
+
    string[] users = new string[3];
+

          
+
    users[0] = "Alice";
+
    users[1] = "Bob";
+
    users[2] = "Charlie";
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+

          
+
Class Sample
+
  Shared Sub Main()
+

          
+
    ' 複数の変数
+
    Dim user0 As String = "Alice"
+
    Dim user1 As String = "Bob"
+
    Dim user2 As String = "Charlie"
+

          
+
    ' 配列
+
    Dim users(2) As String
+

          
+
    users(0) = "Alice"
+
    users(1) = "Bob"
+
    users(2) = "Charlie"
+

          
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
上記の例で言えば、``user0``, ``user1``, ``user2``の各変数は名前から関連性が示唆されるものの独立した値として存在します。 一方``users``は、インデックスによって個々の値が区別されると同時に、その値の集合全体にも名前が与えられていて、ひとまとめの値として存在します。
+

          
+
#column
+
複数の変数
+
|~user0|``"Alice"``|
+

          
+
|~user1|``"Bob"``|
+

          
+
|~user2|``"Charlie"``|
+
#column
+
配列
+
|>|~users|
+
|~0|``"Alice"``|
+
|~1|``"Bob"``|
+
|~2|``"Charlie"``|
+
#column-end
 

        

        
 

        

        
 
*配列の作成
*配列の作成
~
言語によって構文に多少の違いはありますが、配列を作成するには、次のように格納される要素の型と格納できる要素数(配列の長さ)を指定して行います。 構文は似通っていますが、C#では''格納できる要素数''、VBでは''インデックスの最大値''を指定するという間違いやすい相違点があるので、両言語を並行して扱う際は注意が必要です。
言語によって構文に多少の違いはありますが、配列を作成するには、次のように格納される要素の型と格納できる要素数(配列の長さ)を指定して行います。 構文は似通っていますが、C#では''格納できる要素数''、VBでは''インデックスの最大値''を指定するという間違いやすい相違点があるので注意が必要です。
 

        

        
 
#tabpage(codelang=cs,container-title=配列の作成)
#tabpage(codelang=cs,container-title=配列の作成)
 
#code{{
#code{{
127,18 63,12
 
}}
}}
 
#tabpage-end
#tabpage-end
 

        

        
~
上記の例のように長さ(要素数)が0の配列(=要素が1つも格納されない配列)も作成することが出来ます。 長さ・要素数を0には出来ますが、当然マイナスにすることは出来ません。
必要となるケースは稀ですが、上記の例のように長さ・要素数が0の配列(要素を格納できない配列)も作成することが出来ます。 長さ・要素数を0には出来ますが、当然マイナスにすることは出来ません。
 

        

        
+
#remarks
+
長さが0の配列については後述の[[#empty_array]]でも詳しく解説します。
+
#remarks-end
 

        

        
+
#remarks
+
配列の作成方法のバリエーションについては後述の[[#declaration_and_initialization]]を参照してください。
+
#remarks-end
 

        

        
 
*要素の参照
*要素の参照
~
.NET Frameworkにおける配列では、要素のインデックス(通番・要素の番号)は''0を基準''とします(''zero-based'')。 つまり、最初の要素のインデックスは0、その次の要素のインデックスは1、さらにその次は2…、となります。 以降の解説でも、0番目とは最初の要素を指すものとして説明していきます。 C#では配列の変数に続けてかぎ括弧 ''[ ]''、VBでは丸括弧 ''( )''を使ってインデックスを指定します。
.NET Frameworkにおける配列では、要素のインデックス(通番・要素の番号)は''0を基準''とします。 つまり、最初の要素のインデックスは0、その次の要素のインデックスは1、さらにその次は2…、となります。 以降の解説でも、0番目とは最初の要素を指すものとして説明していきます。 C#では配列の変数に続けてかぎ括弧 ''[ ]''、VBでは丸括弧 ''( )''を使ってインデックスを指定します。
 

        

        
 
#tabpage(codelang=cs,container-title=配列要素への値の設定と参照)
#tabpage(codelang=cs,container-title=配列要素への値の設定と参照)
 
#code{{
#code{{
154,10 84,8
 
    users[1] = "Bob";       // 配列の1番目の要素として"Bob"を設定
    users[1] = "Bob";       // 配列の1番目の要素として"Bob"を設定
 
    users[2] = "Charlie";   // 配列の2番目(最後)の要素として"Charlie"を設定
    users[2] = "Charlie";   // 配列の2番目(最後)の要素として"Charlie"を設定
 

        

        
~
    // 配列の1番目に格納されているの値を取得して表示
    // 配列の1番目に格納されているの値を表示
~
    string user1 = users[1];
    Console.WriteLine(users[1]);
+

          
+
    Console.WriteLine(user1);
 
  }
  }
 
}
}
 
}}
}}
174,10 102,8
 
    users(1) = "Bob"      ' 配列の1番目の要素として"Bob"を設定
    users(1) = "Bob"      ' 配列の1番目の要素として"Bob"を設定
 
    users(2) = "Charlie"  ' 配列の2番目(最後)の要素として"Charlie"を設定
    users(2) = "Charlie"  ' 配列の2番目(最後)の要素として"Charlie"を設定
 

        

        
~
    ' 配列の1番目に格納されているの値を取得して表示
    ' 配列の1番目に格納されているの値を表示
~
    Dim user1 As String = users(1)
    Console.WriteLine(users(1))
+

          
+
    Console.WriteLine(user1)
 
  End Sub
  End Sub
 
End Class
End Class
 
}}
}}
187,8 113,6
 
Bob
Bob
 
}}
}}
 

        

        
+

          
+

          
 
配列は''固定長''であり、配列を作成するときに格納できる要素数が決定されます。 配列の長さ(格納できる要素数)を超えるインデックスを指定すると実行時に例外&msdn(netfx,type,System.IndexOutOfRangeException){IndexOutOfRangeException};がスローされます。 配列が自動的に拡張されるといったことは行われません。
配列は''固定長''であり、配列を作成するときに格納できる要素数が決定されます。 配列の長さ(格納できる要素数)を超えるインデックスを指定すると実行時に例外&msdn(netfx,type,System.IndexOutOfRangeException){IndexOutOfRangeException};がスローされます。 配列が自動的に拡張されるといったことは行われません。
 

        

        
 
#tabpage(codelang=cs,container-title=配列の長さを超えるインデックスを参照しようとした場合)
#tabpage(codelang=cs,container-title=配列の長さを超えるインデックスを参照しようとした場合)
227,23 151,10
 
   場所 Sample.Main()
   場所 Sample.Main()
 
}}
}}
 

        

        
+
つまり、JavaScript等の言語では認められている次のような操作は、.NET Frameworkにおける配列ではサポートされません。
+

          
+
#code(js,type=fragment,JavaScript等では認められているこのような操作を行うことはできない){{
+
// 配列を作成
+
var users = new Array();
+

          
+
users[2] = "Charlie"; // 配列の2番目に"Charlie"を設定 (ここでarr.length = 3となる)
+
users[3] = "Dave";    // 配列の3番目に"Dave"を設定 (ここでarr.length = 4となる)
+
}}
+

          
 
#remarks
#remarks
~
可変長の配列が必要な場合は、ジェネリックコレクションクラスの一つである[[Listクラス>programming/netfx/collections/2_generic_1_list]]を使うことができます。 ただし、Listクラスでも上記のように途中のインデックスに要素を追加するようなことはできません。
可変長の配列が必要な場合は、ジェネリックコレクションクラスの一つである[[List>programming/netfx/collections/2_generic_1_list]]を使うことが出来ます。
 
#remarks-end
#remarks-end
 

        

        
+
#remarks
+
既存の配列を拡張する必要がある場合は[[Array.Resizeメソッド>programming/netfx/arrays/2_operations#Array.Resize]]を使うことができます。
+
#remarks-end
 

        

        
 

        

        
 
*長さの取得
*長さの取得
302,17 213,11
 
arr3.Length = 0
arr3.Length = 0
 
}}
}}
 

        

        
+
#remarks
+
多次元配列の場合、Lengthプロパティは多次元配列内の''全要素数''を返します。 ([[programming/netfx/arrays/1_multidimensional#multidimensional_rank_length]])
+
#remarks-end
 

        

        
 

        

        
 

        

        
 
*配列の宣言と初期化 [#declaration_and_initialization]
*配列の宣言と初期化 [#declaration_and_initialization]
~
ここまでで紹介した例では、配列変数の宣言と、配列の作成・代入を同時に行っていました。 ここでは配列の宣言と、配列の作成・初期化の方法を分けて見ていきます。
ここまでで紹介した例では、配列変数の宣言と、配列の作成・代入を同時に行っていました。 ここでは配列の宣言と作成・初期化の方法を分けて見ていきます。 まず、配列の宣言について見ていきます。 配列を格納する変数を宣言するには、次のようにします。
+

          
+
**配列の宣言 [#delaration]
+
まず、配列の宣言について見ていきます。 配列を格納する変数を宣言するには、次のようにします。
 

        

        
 
#tabpage(codelang=cs,container-title=配列変数の宣言)
#tabpage(codelang=cs,container-title=配列変数の宣言)
 
#code{{
#code{{
348,12 253,9
 
}}
}}
 
#tabpage-end
#tabpage-end
 

        

        
~
VBでは、丸括弧''( )''を変数名の後ろに付けた場合も、型名の後ろに付けた場合も、同じ配列変数として扱われます。 どちらも意味は同じです。
このようにして宣言した変数は、配列が格納できる変数が用意されるだけで、実際にはどの配列も参照していない(配列の実体を参照していない)状態となっています。 C#では未初期化の変数、VBではヌル参照の変数となります。 ここからさらに配列を作成して代入したり、他の変数が参照している配列やメソッドの戻り値として返される配列などを代入したりする必要があります。 なお、VBでは丸括弧を変数名の後ろに付けても、型名の後ろにつけても同じものとして扱われます。
+

          
+
このようにして宣言した変数は、配列が格納できる変数が用意されるだけで、実際にはどの配列も参照していない(配列の実体を参照していない)状態となっています。 C#では未初期化の変数、VBではヌル参照の変数となります。 この状態から、配列を作成して変数に代入したり、他の変数が参照している配列やメソッドの戻り値として返される配列などを変数に代入したりする必要があります。
 

        

        
~
**配列の初期化 [#initialization]
続いて配列の初期化について見ていきます。 次のようにすることで、配列変数の宣言と同時にその変数に格納する配列を作成することが出来ます。
+
続いて配列の初期化について見ていきます。 次のようにすることで、配列変数の宣言と同時に配列を作成して変数に代入することが出来ます。
 

        

        
 
#tabpage(codelang=cs,container-title=初期値を与えて配列を作成する (配列初期化子))
#tabpage(codelang=cs,container-title=初期値を与えて配列を作成する (配列初期化子))
 
#code{{
#code{{
396,37 298,7
 
}}
}}
 
#tabpage-end
#tabpage-end
 

        

        
~
このコードにおいて、arr1, arr2, arr3はすべて同じ長さで同じ内容が格納された配列となります。 arr4, arr5, arr6も同様に同じ内容が格納されています。 このコードのnew以降の部分は''配列作成式''、中括弧 ''{ }'' の部分は''配列初期化子''と呼ばれます。 配列作成式で配列の長さを指定する場合、配列初期化子で記述されている要素数と合っていないとコンパイルエラーとなります。
このコードにおいて、arr1, arr2, arr3はすべて同じ長さで同じ内容が格納された配列となります。 arr4, arr5, arr6も同様です。 このコードのnew以降の部分は''配列作成式''、中括弧 ''{ }'' の部分は''配列初期化子''と呼ばれます。 配列作成式で配列の長さを指定する場合、配列初期化子で記述されている要素数と合っていないとコンパイルエラーとなります。
+

          
+
#tabpage(codelang=cs,container-title=配列の長さを記述する場合は配列初期化子の要素数と一致していなければならない)
+
#code{{
+
using System;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // 配列の長さと、配列初期化子の要素数が一致していないのでコンパイルエラーとなる
+
    string[] arr = new string[2] {"Alice", "Bob", "Charlie"};
+
    // error CS0847: An array initializer of length `2' was expected
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+

          
+
Class Sample
+
  Shared Sub Main()
+

          
+
    ' 配列の長さと、配列初期化子の要素数が一致していないのでコンパイルエラーとなる
+
    Dim arr As String() = New String(1) {"Alice", "Bob", "Charlie"}
+
    ' error BC30568: 配列初期化子に 1 個の要素が余分に含まれています
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+

          
 

        

        
 
配列初期化子を記述しない場合は、指定された長さの配列が作成されますが、作成される配列内の各要素にはデフォルト値が設定されます。
配列初期化子を記述しない場合は、指定された長さの配列が作成されますが、作成される配列内の各要素にはデフォルト値が設定されます。
 

        

        
464,30 336,24
 
}}
}}
 
#tabpage-end
#tabpage-end
 

        

        
~
デフォルト値は型によって異なりますが、数値などの値型では``0``や``0``に相当する値、文字列型やクラスなどの参照型ではヌル参照(null/Nothing)となります。
デフォルト値は型によって異なりますが、数値などの型では``0``や``0``に相当する値、文字列型を含む参照型ではヌル参照(null/Nothing)となります。
 

        

        
 
#remarks
#remarks
~
型とデフォルト値の詳細については[[programming/netfx/basic_types/0_characteristics#DefaultValue]]、型の種類については[[programming/netfx/valuetype_referencetype]]を参照してください。
型とデフォルト値の詳細については[[programming/netfx/basic_types/0_characteristics#DefaultValue]]を参照してください。
 
#remarks-end
#remarks-end
 

        

        
-
**長さ0の配列
-
長さ0の配列(空の配列)を作成したい場合は次のように記述することが出来ます。
 

        

        
~

          
#tabpage(codelang=cs,container-title=長さが0の配列を作成する)
+
配列初期化子を記述しない場合は、次のように変数に代入されている値を長さとして配列を作成することもできます。 この場合も、各要素にデフォルト値が設定された状態の配列が作成されます。
+

          
+
#tabpage(codelang=cs,container-title=変数で指定された長さの配列を作成する)
 
#code{{
#code{{
 
using System;
using System;
 

        

        
 
class Sample {
class Sample {
 
  static void Main()
  static void Main()
 
  {
  {
~
    int length = 3;
    string[] arr1 = new string[0];
~

          
    string[] arr2 = new string[] {};
+
    // 長さに変数lengthの値を指定して文字列配列を作成する
+
    string[] arr = new string[length];
+

          
+
    // 作成された配列の長さを取得して表示する
+
    Console.WriteLine(arr.Length);
 
  }
  }
 
}
}
 
}}
}}
498,27 364,15
 
Class Sample
Class Sample
 
  Shared Sub Main()
  Shared Sub Main()
 

        

        
~
    Dim length As Integer = 3
    Dim arr1 As String() = New String(-1) {}
~

          
    Dim arr2 As String() = New String() {}
~
    ' 長さに変数lengthの値を指定して文字列配列を作成する
    Dim arr3(-1) As String
+
    Dim arr As String() = New String(length - 1) {}
+

          
+
    ' 作成された配列の長さを取得して表示する
+
    Console.WriteLine(arr.Length)
 

        

        
 
  End Sub
  End Sub
 
End Class
End Class
 
}}
}}
 
#tabpage-end
#tabpage-end
 

        

        
+
#prompt(実行結果){{
+
3
+
}}
+

          
+
**長さ0の配列
+
長さ0の配列(空の配列)の作成については後述の[[#empty_array]]で解説します。
+

          
+

          
 
*配列フィールドの宣言
*配列フィールドの宣言
 
ローカル変数の場合と同様、クラスや構造体のフィールドとしても配列を宣言することもできます。
ローカル変数の場合と同様、クラスや構造体のフィールドとしても配列を宣言することもできます。
 

        

        
552,8 406,6
 
}}
}}
 
#tabpage-end
#tabpage-end
 

        

        
+

          
+

          
 
ただし、構造体内の配列フィールドには初期化子を指定することはできません。 一方、クラスの場合は配列フィールドに初期化子を指定することができます。
ただし、構造体内の配列フィールドには初期化子を指定することはできません。 一方、クラスの場合は配列フィールドに初期化子を指定することができます。
 

        

        
 
#tabpage(codelang=cs,container-title=配列フィールドに初期化子を指定する)
#tabpage(codelang=cs,container-title=配列フィールドに初期化子を指定する)
669,7 521,7
 

        

        
 

        

        
 
*要素の列挙
*要素の列挙
~
配列内の各要素を列挙するには、for文とforeach文が使えます。 for文では配列のインデックスを使って各要素を参照するのに対し、foreach文では個別の変数によって列挙された各要素を参照します。
配列内の各要素を列挙するには、for文とforeach文が使えます。 for文では配列のインデックスを使って各要素を参照するのに対し、foreach文では列挙子を使って各要素を参照します。 列挙子とforeach文の関係については[[programming/netfx/enumerator/0_enumerable_enumerator]]で詳しく解説しています。
 

        

        
 
#tabpage(codelang=cs,container-title=forとforeachによる配列内の要素の列挙)
#tabpage(codelang=cs,container-title=forとforeachによる配列内の要素の列挙)
 
#code{{
#code{{
690,7 542,6
 
    Console.WriteLine();
    Console.WriteLine();
 

        

        
 
    // foreach文を使って配列内の各要素を列挙
    // foreach文を使って配列内の各要素を列挙
+
    // (列挙した各要素は変数elemに代入される)
 
    foreach (string elem in arr)
    foreach (string elem in arr)
 
    {
    {
 
      Console.WriteLine(elem);
      Console.WriteLine(elem);
715,7 566,6
 
    Console.WriteLine()
    Console.WriteLine()
 

        

        
 
    ' For Eachステートメントを使って配列内の各要素を列挙
    ' For Eachステートメントを使って配列内の各要素を列挙
+
    ' (列挙した各要素は変数elemに代入される)
 
    For Each elem As String In arr
    For Each elem As String In arr
 
      Console.WriteLine(elem)
      Console.WriteLine(elem)
 
    Next
    Next
736,926 586,17
 

        

        
 
foreach文では常に配列の先頭から一つずつ列挙されるため、配列の末尾から先頭に向けて列挙したり、一つ飛ばしで列挙したりといったことは出来ません。 そういった列挙が必要な場合はforeach文ではなくfor文を使って記述する必要があります。
foreach文では常に配列の先頭から一つずつ列挙されるため、配列の末尾から先頭に向けて列挙したり、一つ飛ばしで列挙したりといったことは出来ません。 そういった列挙が必要な場合はforeach文ではなくfor文を使って記述する必要があります。
 

        

        
~
for文とforeach文の使い分けは概ね以下のようになると言えます。
言い換えるなら、列挙する際に要素の位置(インデックス)が重要となる場合はfor文、位置(インデックス)が重要でない場合はforeach文というように使い分けることが出来ます。
+
:for文|列挙する際に要素の位置(インデックス)が重要となる場合
+
インデックスによって各要素に対して行う処理を振り分けたい場合(インデックス&var{n};以上の要素だけ参照したい、インデックスが&var{n};のときだけ処理を行いたいなど)
+
:foreach文|列挙する際に要素の位置(インデックス)が重要でない場合
+
インデックスに関わらずすべての要素に同じ処理を行いたい場合
+

          
+
#remarks
+
配列内から条件に合う要素を検索・取得したりするにはArrayクラスの[[FindメソッドやExistsメソッドなど>programming/netfx/arrays/2_operations#Array.Find]]を使うことができます。 また、配列内の要素の順番を逆にして列挙したい場合は[[Reverseメソッド>programming/netfx/arrays/2_operations#Array.Reverse]]を使うことができます。
+
#remarks-end
+

          
+
#remarks
+
for文とforeach文による配列の列挙では、パフォーマンス上の差はほとんどありません。
+
#remarks-end
+

          
+
#remarks
+
foreach文での列挙は配列に実装されているIEnumerableインターフェイスから提供される機能によって実現しています。 配列とIEnumerableインターフェイスについては後述の[[#array_interfaces]]、IEnumerableインターフェイスと列挙については[[programming/netfx/enumerator/0_enumerable_enumerator]]で詳しく解説しています。
+
#remarks-end
+

          
+

          
+

          
+
*要素の検索・ソート、配列全体への変更
+
配列内にある要素を検索する、ソートを行う、また配列のサイズを変更する、コピーする、配列全体の型変換を行うといった操作は、Arrayクラスに用意されているユーティリティメソッドを使うことで行うことができます。 Arrayクラスを使った配列の操作については[[programming/netfx/arrays/2_operations]]で解説しています。
+

          
+
また、ソートに関しては個別に[[programming/netfx/sorting/0_basictypes]]でも詳しく解説しています。
+

          
+

          
+
*空の配列 [#empty_array]
+
.NET Frameworkでは''空の配列''を作成することができます。 空の配列とは、''長さが0''で''要素が1つも格納されていない''あるいは''1つも格納できない''配列です。
+

          
+
**構文を用いた作成
+
空の配列(長さ0の配列)を作成したい場合は次のように記述することができます。
+

          
+
#tabpage(codelang=cs,container-title=空の配列(長さが0の配列)を作成する)
+
#code{{
+
using System;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // 以下のいずれも空の配列となる
+
    string[] arr1 = new string[0];
+
    string[] arr2 = new string[] {};
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+

          
+
Class Sample
+
  Shared Sub Main()
+

          
+
    ' 以下のいずれも空の配列となる
+
    Dim arr1 As String() = New String(-1) {}
+
    Dim arr2 As String() = New String() {}
+
    Dim arr3(-1) As String
+

          
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
空の配列はヌル参照の状態とは明確に異なります。 配列は参照しているが、その配列にはなにも格納されていない状態になります。
+

          
+
#tabpage(codelang=cs,container-title=空の配列が代入された配列変数とヌル参照の配列変数の違い)
+
#code{{
+
using System;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    string[] arrEmpty = new string[0];
+

          
+
    // 空の配列ではプロパティの参照などを行うことができる
+
    Console.WriteLine(arrEmpty.Length);
+

          
+
    string[] arrNull = null;
+

          
+
    // ヌル参照の配列変数ではプロパティの参照などを行うことはできない
+
    Console.WriteLine(arrNull.Length); // NullReferenceExceptionがスローされる
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+

          
+
Class Sample
+
  Shared Sub Main()
+

          
+
    Dim arrEmpty As String() = New String() {}
+

          
+
    ' 空の配列ではプロパティの参照などを行うことができる
+
    Console.WriteLine(arrEmpty.Length)
+

          
+
    Dim arrNull As String() = Nothing
+

          
+
    ' ヌル参照の配列変数ではプロパティの参照などを行うことはできない
+
    Console.WriteLine(arrNull.Length) ' NullReferenceExceptionがスローされる
+

          
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
**Array.Emptyメソッドを用いた作成 [#Array.Empty]
+
.NET Framework 4.6以降では&msdn(netfx,member,System.Array.Empty){Array.Empty<T>メソッド};を使うことでも空の配列を取得することができます。 それより前のバージョンでは、&msdn(netfx,member,System.Linq.Enumerable.Empty){Emumerable.Emptyメソッド};の戻り値に対して&msdn(netfx,member,System.Linq.Enumerable.ToArray){ToArrayメソッド};を呼び出すことで空の配列を作成することができます。
+

          
+
#tabpage(codelang=cs,container-title=Array.Emptyメソッド・Enumerable.Emptyメソッドを使って空の配列を作成する)
+
#code{{
+
using System;
+
using System.Linq;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // Array.Emptyメソッドを使って空の配列を取得する(.NET Framework 4.6以降)
+
    string[] arr1 = Array.Empty<string>();
+
    int[] arr2 = Array.Empty<int>();
+

          
+
    // Enumerable.Emptyメソッドを使って空の配列を作成する(.NET Framework 3.5以降)
+
    string[] arr3 = Enumerable.Empty<string>().ToArray();
+
    int[] arr4 = Enumerable.Empty<int>().ToArray();
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+

          
+
Class Sample
+
  Shared Sub Main()
+

          
+
    ' Array.Emptyメソッドを使って空の配列を取得する(.NET Framework 4.6以降)
+
    Dim arr1 As String() = Array.Empty(Of String)()
+
    Dim arr2 As Integer() = Array.Empty(Of Integer)()
+

          
+
    ' Enumerable.Emptyメソッドを使って空の配列を作成する(.NET Framework 3.5以降)
+
    Dim arr3 As String() = Enumerable.Empty(Of String)().ToArray()
+
    Dim arr4 As Integer() = Enumerable.Empty(Of Integer)().ToArray()
+

          
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#remarks
+

          
+
呼び出される回数が膨大で配列の生成コストが無視できないようなメソッドや、使用可能なメモリが極端にシビアな実行環境などでは、空の配列を都度作成・取得するよりも、あらかじめキャッシュしておいたインスタンスを使用するようにするか、&msdn(netfx,member,System.Type.EmptyTypes){Type.EmptyTypes};のようにあらかじめ用意された空の配列を使用することでパフォーマンスを向上させることができます。
+

          
+
#remarks-end
 

        

        
 
#remarks
#remarks
~
Array.Emptyメソッドが常にキャッシュされたインスタンスを返すかどうか、呼び出しの度に空の配列のインスタンスを作成するのかどうかについてはドキュメントには明記されていません。
配列内の要素の順番を逆にしたい場合は[[Array.Reverseメソッド>programming/netfx/arrays/2_operations#Array.Reverse]]を使うことが出来ます。
+

          
+
一方、Emumerable.Emptyメソッドでは以下のように記載されているため常にキャッシュされた空のシーケンスを返すことが保証されています。
+

          
+
>Empty<TResult>() メソッドは、TResult 型の空のシーケンスをキャッシュします。
+

          
+
しかし、``Enumerable.Empty<T>().ToArray()``の呼び出しでは、ToArrayメソッドが空のシーケンスから配列の作成を行うため呼び出しの度に空の配列のインスタンスが作成されます。
+

          
 
#remarks-end
#remarks-end
 

        

        
 

        

        
-
*その他の操作
-
.NET Frameworkにおける配列は暗黙的に[[Arrayクラス>programming/netfx/arrays/2_operations]]を継承しています。 Arrayクラスには配列のソート・リサイズ・コピーなどを行うメソッドが用意されています。 Arrayクラスを使った配列の操作については[[programming/netfx/arrays/2_operations]]で解説します。
 

        

        
~
**ヌル参照と空の配列・戻り値や初期値としての空の配列
また、配列(Arrayクラス)はIEnumerable, ICollection, IListなどのインターフェイスを実装していて、配列も一種の[[コレクション>programming/netfx/collections/0_abstract]]として扱うことができます。 配列もIListなどのインターフェイスにキャストして操作を行うことは可能ですが、固定長であるためAdd/Removeなどサイズを変更するような操作を行うことはできません。 配列が実装するインターフェイスや他のコレクションとの特徴の違いについては[[programming/netfx/collections/0_abstract#characteristics]]を参照してください。
+
配列を返すメソッドでは、``null``/``Nothing``よりも空の配列を返したほうがよい場合があります。 配列を返すメソッドがnullを返す場合、呼び出し側は戻り値がnullかどうかの判定を行った上で列挙などの操作を行う必要がありますが、空の配列を返すようにすれば呼び出し側はnull判定を行わずに戻り値の配列に操作を行うことができます。
+

          
+
#tabpage(codelang=cs,container-title=空の配列を返すメソッド)
+
#code{{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  // ファイルから複数の値を読み込むメソッド
+
  static int[] ReadValuesFromFile(string file)
+
  {
+
    if (File.Exists(file)) {
+
      int[] values;
+

          
+
      // ファイルを開いて読み込んだが、読み込み対象の値が無かった場合を想定する
+
      // 値が無かったことを表すため、nullではなく空の配列を返す
+
      values = new int[0];
+

          
+
      return values;
+
    }
+
    else {
+
      throw new FileNotFoundException("ファイルがありません", file);
+
    }
+
  }
+

          
+
  static void Main()
+
  {
+
    // ファイルから読み込んだ値を列挙する
+
    // (ファイルに目的の値がなかった場合でもメソッドは空の配列を返すため、
+
    // null判定を行うことなく列挙を行うことができる)
+
    foreach (int val in ReadValuesFromFile("data.txt")) {
+
      Console.WriteLine(val);
+
    }
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  ' ファイルから複数の値を読み込むメソッド
+
  Shared Function ReadValuesFromFile(ByVal file As String) As Integer()
+

          
+
    If File.Exists(file) Then
+
      Dim values() As Integer
+

          
+
      ' ファイルを開いて読み込んだが、読み込み対象の値が無かった場合を想定する
+
      ' 値が無かったことを表すため、Nothingではなく空の配列を返す
+
      values = New Integer() {}
+

          
+
      Return values
+
    Else
+
      Throw New FileNotFoundException("ファイルがありません", file)
+
    End If
+

          
+
  End Function
+

          
+
  Shared Sub Main()
+

          
+
    ' ファイルから読み込んだ値を列挙する
+
    ' (ファイルに目的の値がなかった場合でもメソッドは空の配列を返すため、
+
    ' null判定を行うことなく列挙を行うことができる)
+
    For Each val As Integer In ReadValuesFromFile("data.txt")
+
      Console.WriteLine(val)
+
    Next
+

          
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
上記の例では、ファイルが無かった場合にもnullや空の配列を返すようにすることもできますが、推奨できません。 例えば、上記のメソッドにエラー処理を追加してファイルの内容が異常だった場合にもnullを返すような実装にした場合、メソッドの呼び出し側は戻り値がnullとなった原因が何なのかを知ることができません。
+

          
+
このため、なんらかのエラーがあった場合には、nullや空の配列を返すよりも、ファイルが無かった場合は&msdn(netfx,type,System.IO.FileNotFoundException){FileNotFoundException};、ファイルの内容やフォーマットが異常だった場合は&msdn(netfx,type,System.IO.InvalidDataException){InvalidDataException};をスローするというように、状況にあった例外をスローして呼び出し側に原因を通知すべきです。
+

          
+

          
+

          
+
配列フィールドでも、初期値として``null``/``Nothing``の代わりに空の配列を指定しておくことができます。 メソッドの場合と同様、初期値として空の配列を指定しておくことでnull判定をせずに配列フィールドの参照ができるようになります。
+

          
+
#tabpage(codelang=cs,container-title=初期値として空の配列を設定したフィールド)
+
#code{{
+
class Account {
+
  public string Name;
+
  public string[] Address = new string[0]; // 初期値として空の配列を代入しておく
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Class Account
+
  Public Name As String
+
  Public Address() As String = New String() {} ' 初期値として空の配列を代入しておく
+
End Class
+
}}
+
#tabpage-end
+

          
+
一方この場合、空の配列よりも``null``/``Nothing``の方が初期値として妥当な場合もあります。 例えば、このフィールドがデータベースからの参照やユーザー入力によって設定されるものであれば、まだ設定が行われていないことを表す目的でnullを初期値としておいたほうが妥当と考えることもできます。 (もちろん、未入力を表すフラグは別に用意し、初期値は空の配列にしておく、という選択もありえます。)
+

          
+

          
+

          
+
このように、空の配列を用いることでヌル判定やヌル参照の状況をさけることができる一方で、空の配列とヌル参照では意味が全く異なるため、空の配列とヌル参照を混同したり、単純に置き換えることはできません。 どちらがより妥当か十分検討する必要があります。
+

          
+

          
+
*配列のインターフェイス [#array_interfaces]
+
配列(厳密には配列の基底クラスである&msdn(netfx,type,System.Array){Arrayクラス};)は、&msdn(netfx,type,System.Collections.IEnumerable){IEnumerable};, &msdn(netfx,type,System.Collections.ICollection){ICollection};, &msdn(netfx,type,System.Collections.IList){IList};などのインターフェイスを実装しています。 これにより、配列も一種の[[コレクション>programming/netfx/collections/0_abstract]]として、他のコレクションと同等に扱うことができるようになっています。
+

          
+
例えば、IEnumerableまたはIEnumerable<T>を引数にとるメソッドでは配列を指定することができます。 &msdn(netfx,member,System.String.Concat){String.Concatメソッド};(.NET Framework 4以降)では、任意の型``T``のIEnumerable<T>を引数にとることができます。 このメソッドに配列を指定することができ、配列内の各要素の値を結合した文字列を取得することができます。
+

          
+
#tabpage(codelang=cs,container-title=String.Concatメソッドを使って配列内の値を結合した文字列を作成する)
+
#code{{
+
using System;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    int[] arr = {0, 1, 2, 3, 4};
+

          
+
    string s = string.Concat(arr);
+

          
+
    Console.WriteLine(s);
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+

          
+
Class Sample
+
  Shared Sub Main()
+

          
+
    Dim arr As Integer() = {0, 1, 2, 3, 4}
+

          
+
    Dim s As String = String.Concat(arr)
+

          
+
    Console.WriteLine(s)
+

          
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
01234
+
}}
+

          
+
また&msdn(netfx,member,System.Linq.Enumerable.Where){Where};などのLINQの各メソッドもIEnumerable<T>を引数にとりますが、配列はIEnumerable<T>を実装しているため配列に対してもLINQのメソッドを使用することができます。
+

          
+
#tabpage(codelang=cs,container-title=LINQのメソッドを使って配列を操作する)
+
#code{{
+
using System;
+
using System.Linq;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    int[] arr = {0, 1, 2, 3, 4};
+

          
+
    // 配列の中にある奇数の要素のみを抽出し、そのうち最大のものを取得して表示する
+
    Console.WriteLine(arr.Where(e => e % 2 != 0).Max());
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Linq
+

          
+
Class Sample
+
  Shared Sub Main()
+

          
+
    Dim arr As Integer() = {0, 1, 2, 3, 4}
+

          
+
    ' 配列の中にある奇数の要素のみを抽出し、そのうち最大のものを取得して表示する
+
    Console.WriteLine(arr.Where(Function(e) e Mod 2 <> 0).Max())
+

          
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
3
+
}}
+

          
+

          
+

          
+
配列がICollectionなどのインターフェイスを実装しているといっても、その機能のすべてがサポートされるわけではありません。 たとえば、配列をICollectionインターフェイスにキャストして操作することは可能ですが、&msdn(netfx,member,System.Collections.Generic.ICollection`1.Add){ICollection.Add};や&msdn(netfx,member,System.Collections.Generic.ICollection`1.Remove){ICollection.Remove};などのメソッドを呼び出して配列のサイズを変更するような操作を行うことはできません。 このような操作を行おうとした場合には&msdn(netfx,type,System.NotSupportedException){NotSupportedException};がスローされます。
+

          
+
#tabpage(codelang=cs,container-title=ICollectionインターフェイスを介して配列ではサポートされないメソッドを呼び出す場合)
+
#code{{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    int[] arr = {0, 1, 2, 3, 4};
+

          
+
    // 配列をICollection<T>インターフェイスにキャスト
+
    ICollection<int> coll = arr;
+

          
+
    // ICollectionインターフェイスを介して要素を追加しようとしても、
+
    // 配列は固定長であるためNotSupportedExceptionがスローされる
+
    coll.Add(5);
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Shared Sub Main()
+

          
+
    Dim arr As Integer() = {0, 1, 2, 3, 4}
+

          
+
    ' 配列をICollection(Of T)インターフェイスにキャスト
+
    Dim coll As ICollection(Of Integer) = arr
+

          
+
    ' ICollectionインターフェイスを介して要素を追加しようとしても、
+
    ' 配列は固定長であるためNotSupportedExceptionがスローされる
+
    coll.Add(5)
+

          
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
System.NotSupportedException: コレクションは固定サイズです。
+
   at System.SZArrayHelper.Add[T](T value)
+
   at Sample.Main(String[] args)
+
}}
+

          
+
#remarks
+
配列が実装するインターフェイスや他のコレクションとの特徴の違いについては[[programming/netfx/collections/0_abstract#characteristics]]を参照してください。
+
#remarks-end
+

          
+

          
+

          
+

          
+
*配列の使用と代替手段
+
ここでは配列が適用できる場合と、それが不適切となる場合、またその場合の代替手段やより適切な実装方法などについて解説します。
+

          
+
**object配列
+
object型の配列では任意の型の値を格納することができますが、object配列が必要になる場面はそう多くなく、また必要になった場合でもそれはデータ構造を定めていないことによる不適切な実装である可能性があります。
+

          
+
#tabpage(codelang=cs,container-title=object配列を使って複数のデータ型の値を格納する)
+
#code{{
+
using System;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    object[] data = new object[4];
+

          
+
    data[0] = "Alice";
+
    data[1] = 24;
+
    data[2] = "Bob";
+
    data[3] = 16;
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+

          
+
Class Sample
+
  Shared Sub Main()
+

          
+
    Dim data(3) As Object
+

          
+
    data(0) = "Alice"
+
    data(1) = 24
+
    data(2) = "Bob"
+
    data(3) = 16
+

          
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
こういった場合、格納するデータの構造をクラスや構造体で適切に定め、それに対応した配列型を使用すべきです。 安易にobject型配列を用いる前に、データ構造が適切に定められているか、既存の型を使ってデータを扱えないか検討してください。
+

          
+
#tabpage(codelang=cs,container-title=独自に定義したデータ型を使って値を配列に格納する)
+
#code{{
+
using System;
+

          
+
// 配列に格納するデータの構造を表すクラス
+
class Account {
+
  public string Name;
+
  public int Age;
+
}
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    Account[] accounts = new Account[2];
+

          
+
    accounts[0] = new Account() {Name = "Alice", Age = 24};
+
    accounts[1] = new Account() {Name = "Bob", Age = 16};
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+

          
+
Class Account
+
  Public Name As String
+
  Public Age As Integer
+
End Class
+

          
+
Class Sample
+
  Shared Sub Main()
+

          
+
    Dim accounts(1) As Account
+

          
+
    accounts(0) = New Account() With {.Name = "Alice", .Age = 24}
+
    accounts(1) = New Account() With {.Name = "Bob", .Age = 16}
+

          
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+

          
+
**可変長の引数
+
引数で配列を指定することにより、任意個の値をメソッドに渡すことができます。 この場合、あらかじめ引数に渡す値を配列としてまとめておく必要があります。
+

          
+
#tabpage(codelang=cs,container-title=配列を使って引数に任意個の値を渡す)
+
#code{{
+
using System;
+

          
+
class Sample {
+
  // 引数で与えられた配列の合計を求めるメソッド
+
  static long Sum(int[] arr)
+
  {
+
    long sum = 0L;
+

          
+
    foreach (int val in arr) {
+
      sum += val;
+
    }
+

          
+
    return sum;
+
  }
+

          
+
  static void Main()
+
  {
+
    int[] arr = new int[] {2, 5, 3, 8, 4};
+

          
+
    Console.WriteLine("合計 = {0}", Sum(arr));
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+

          
+
Class Sample
+
  ' 引数で与えられた配列の合計を求めるメソッド
+
  Shared Function Sum(ByVal arr() As Integer) As Long
+

          
+
    Dim sum As Long = 0L
+

          
+
    For Each val As Integer In arr
+
      sum += val
+
    Next
+

          
+
    Return sum
+

          
+
  End Function
+

          
+
  Shared Sub Main()
+

          
+
    Dim arr() As Integer = New Integer() {2, 5, 3, 8, 4}
+

          
+
    Console.WriteLine("合計 = {0}", Sum(arr))
+

          
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+

          
+

          
+
配列型の引数とは別に、``params``キーワード(C#)・``ParamArray``キーワード(VB)を使うことにより、引数を可変長とすることができます。 可変長の引数では、引数に渡す値は必ずしも配列にする必要はありません(配列を直接渡すこともできます)。 メソッド側では、可変長引数は通常の配列と同様に扱うことができます。
+

          
+
#tabpage(codelang=cs,container-title=可変長引数を使って任意個の値を渡す)
+
#code{{
+
using System;
+

          
+
class Sample {
+
  // 引数で与えられた複数の値の合計を求めるメソッド
+
  static long Sum(params int[] arr)
+
  {
+
    long sum = 0L;
+

          
+
    foreach (int val in arr) {
+
      sum += val;
+
    }
+

          
+
    return sum;
+
  }
+

          
+
  static void Main()
+
  {
+
    Console.WriteLine("合計 = {0}", Sum(2, 5, 3));
+
    Console.WriteLine("合計 = {0}", Sum(2, 5, 3, 8, 4));
+
    Console.WriteLine("合計 = {0}", Sum(new int[] {2, 5, 3, 8, 4})); // 配列を渡すこともできる
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+

          
+
Class Sample
+
  ' 引数で与えられた配列の合計を求めるメソッド
+
  Shared Function Sum(ByVal ParamArray arr() As Integer) As Long
+

          
+
    Dim sum As Long = 0L
+

          
+
    For Each val As Integer In arr
+
      sum += val
+
    Next
+

          
+
    Return sum
+

          
+
  End Function
+

          
+
  Shared Sub Main()
+

          
+
    Console.WriteLine("合計 = {0}", Sum(2, 5, 3))
+
    Console.WriteLine("合計 = {0}", Sum(2, 5, 3, 8, 4))
+
    Console.WriteLine("合計 = {0}", Sum(New Integer() {2, 5, 3, 8, 4})) ' 配列を渡すこともできる
+

          
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#remarks
+
可変長引数は、必ずメソッドの一番最後の引数でなければなりません。 例えば、可変長引数のあとに通常の引数をとるようなメソッドを作成することはできません。
+

          
+
#tabpage(codelang=cs,container-title=可変長引数を定義できる位置)
+
#code(type=fragment){{
+
// このように通常の引数のあとに可変長引数をとるようなメソッドは宣言できる
+
void ParamsMethodOK(int firstValue, params int[] values) {}
+

          
+
// このように可変長引数のあとに通常の引数をとるようなメソッドは宣言できない
+
void ParamsMethodNG(params int[] values, int lastValue) {}
+
}}
+
#tabpage(codelang=vb)
+
#code(type=fragment){{
+
' このように通常の引数のあとに可変長引数をとるようなメソッドは宣言できる
+
Sub ParamsMethodOK(ByVal firstValue As Integer, ByVal ParamArray values() As Integer)
+
End Sub
+

          
+
' このように可変長引数のあとに通常の引数をとるようなメソッドは宣言できない
+
Sub ParamsMethodNG(ByVal ParamArray values() As Integer, ByVal lastValue As Integer)
+
End Sub
+
}}
+
#tabpage-end
+

          
+
#remarks-end
+

          
+
可変長引数の型をobjectにすることにより、任意の型の値を任意個とることができるようになります。 例えば、&msdn(netfx,member,System.Console.WriteLine){Console.WriteLineメソッド};や&msdn(netfx,member,System.String.Join){String.Joinメソッド};ではobject型の可変長引数をとることができるようになっています。
+

          
+

          
+
**複数の戻り値
+
メソッドの戻り値を配列にすることでメソッドから複数の値を返すことができます。 しかし、例えば意味の異なる値を配列でひとまとめにして返すようにすると、格納されている値の意味があいまいになり、また呼び出し側では戻り値を配列から展開する必要があります。
+

          
+
#tabpage(codelang=cs,container-title=商と剰余を配列に格納して返すメソッド)
+
#code{{
+
using System;
+

          
+
class Sample {
+
  // xとyの商と剰余を求めるメソッド
+
  // 商は戻り値のインデックス0、剰余はインデックス1に格納する
+
  static int[] DivRem(int x, int y)
+
  {
+
    int[] ret = new int[2];
+

          
+
    ret[0] = x / y;
+
    ret[1] = x % y;
+

          
+
    return ret;
+
  }
+

          
+
  static void Main()
+
  {
+
    // 7÷3の商と剰余を求めたい
+
    int[] ret = DivRem(7, 3);
+

          
+
    // 戻り値から商と剰余に展開しなければならない
+
    // また戻り値の配列に格納されている値の意味があいまいになる
+
    int div = ret[0];
+
    int rem = ret[1];
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+

          
+
Class Sample
+
  ' xとyの商と剰余を求めるメソッド
+
  ' 商は戻り値のインデックス0、剰余はインデックス1に格納する
+
  Shared Function DivRem(ByVal x As Integer, ByVal y As Integer) As Integer()
+

          
+
    Dim ret(2) As Integer
+

          
+
    ret(0) = x \ y
+
    ret(1) = x Mod y
+

          
+
    Return ret
+

          
+
  End Function
+

          
+
  Shared Sub Main()
+

          
+
    ' 7÷3の商と剰余を同時に求めたい
+
    Dim ret() As Integer = DivRem(7, 3)
+

          
+
    ' 戻り値から商と剰余に展開しなければならない
+
    ' また戻り値の配列に格納されている値の意味があいまいになる
+
    Dim div As Integer = ret(0)
+
    Dim remn As Integer = ret(1)
+

          
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
このような場合は、配列よりも''outパラメータ''(VBでは''ByRef引数'')を使ったほうがより適切です。
+

          
+
#tabpage(codelang=cs,container-title=商と剰余をoutパラメータ・ByRef引数に格納して返すメソッド)
+
#code{{
+
using System;
+

          
+
class Sample {
+
  // xとyの商と剰余を求めるメソッド
+
  // 商は第3引数のoutパラメータ、剰余は第4引数のoutパラメータに格納する
+
  static void DivRem(int x, int y, out int div, out int rem)
+
  {
+
    div = x / y;
+
    rem = x % y;
+
  }
+

          
+
  static void Main()
+
  {
+
    // 7÷3の商と剰余を求めたい
+
    int div, rem;
+

          
+
    DivRem(7, 3, out div, out rem);
+

          
+
    // メソッドの呼び出し後、変数divとremに結果が格納される
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+

          
+
Class Sample
+
  ' xとyの商と剰余を求めるメソッド
+
  ' 商は第3引数のByRef引数、剰余は第4引数のByRef引数に格納する
+
  Shared Sub DivRem(ByVal x As Integer, ByVal y As Integer, ByRef div As Integer, ByRef remn As Integer)
+

          
+
    div = x \ y
+
    remn = x Mod y
+

          
+
  End Sub
+

          
+
  Shared Sub Main()
+

          
+
    ' 7÷3の商と剰余を同時に求めたい
+
    Dim div As Integer, remn As Integer
+

          
+
    DivRem(7, 3, div, remn)
+

          
+
    ' メソッドの呼び出し後、変数divとremnに結果が格納される
+

          
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
outパラメータ・ByRef引数はメソッドの戻り値と併用することもできます。 実際、.NET Frameworkで用意されている商と剰余を求める&msdn(netfx,member,System.Math.DivRem){Math.DivRemメソッド};では、商は戻り値として、剰余はoutパラメータで返されるようになっています。
+

          
+
#remarks
+
Math.DivRemメソッドについては[[programming/netfx/mathematics/0_math#FuncMulDiv]]を参照してください。
+
#remarks-end
+

          
+

          
+

          
+
これとは異なる方法で複数の値を返す手段として、&msdn(netfx,type,System.Tuple){Tuple型};(タプル)を利用することもできます。 Tuple型は複数の値をひとまとめにするという点は配列と似ていますが、異なる型同士でもまとめることができる点で配列とは異なります。 これにより、配列では値を複数返す場合でも同じ型に限られるのに対し、Tuple型を用いれば型の異なる複数の値を返すことができます。
+

          
+
#tabpage(codelang=cs,container-title=Tuple型を使って合計と平均を返すメソッド)
+
#code{{
+
using System;
+

          
+
class Sample {
+
  // 引数で与えられた配列の合計と平均を求めるメソッド
+
  // 合計はTuple.Item1, 平均はTuple.Item2に格納する
+
  static Tuple<long, double> SumAvr(int[] arr)
+
  {
+
    long sum = 0L;
+

          
+
    foreach (int val in arr) {
+
      sum += val;
+
    }
+

          
+
    double avr = sum / (double)arr.Length;
+

          
+
    // Item1にsum, Item2にavrの値を格納したTupleを作成して返す
+
    return Tuple.Create(sum, avr);
+
  }
+

          
+
  static void Main()
+
  {
+
    // この配列内の要素の合計と平均を求めたい
+
    int[] arr = new int[] {2, 5, 3, 8, 4};
+

          
+
    Tuple<long, double> ret = SumAvr(arr);
+

          
+
    Console.WriteLine("合計 = {0}", ret.Item1);
+
    Console.WriteLine("平均 = {0}", ret.Item2);
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+

          
+
Class Sample
+
  ' 引数で与えられた配列の合計と平均を求めるメソッド
+
  ' 合計はTuple.Item1, 平均はTuple.Item2に格納する
+
  Shared Function SumAvr(ByVal arr() As Integer) As Tuple(Of Long, Double)
+

          
+
    Dim sum As Long = 0L
+

          
+
    For Each val As Integer In arr
+
      sum += val
+
    Next
+

          
+
    Dim avr As Double = sum / arr.Length
+

          
+
    ' Item1にsum, Item2にavrの値を格納したTupleを作成して返す
+
    Return Tuple.Create(sum, avr)
+

          
+
  End Function
+

          
+
  Shared Sub Main()
+

          
+
    ' この配列内の要素の合計と平均を求めたい
+
    Dim arr() As Integer = New Integer() {2, 5, 3, 8, 4}
+

          
+
    Dim ret As Tuple(Of Long, Double) = SumAvr(arr)
+

          
+
    Console.WriteLine("合計 = {0}", ret.Item1)
+
    Console.WriteLine("平均 = {0}", ret.Item2)
+

          
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
このように、配列と違ってTuple型では型の異なる値をひとまとめにできる利点がある一方、Tuple型では格納されている値を参照するのにItem1, Item2といったメンバ名で参照する必要があるため、配列同様に格納されている値の意味があいまいになるという欠点もあります。
+

          
+

          
+

          
+
なお、複数のスカラー値をタプルや配列を返したり、タプルや配列で返される戻り値を変数(スカラー値)に展開するための以下のような構文は、C# 6.0、VB14(Visual Basic 2015)時点では用意されていません。 (このような機能の将来的な導入については検討がされています)
+

          
+
#tabpage(codelang=cs,container-title=複数の戻り値をスカラー値に展開する構文(擬似コード、実際にはコンパイルできない))
+
#code{{
+
using System;
+

          
+
class Sample {
+
  // 引数で与えられた配列の合計と平均を同時に返すメソッド
+
  static (long, double) SumAvr(int[] arr)
+
  {
+
    long sum = 0L;
+

          
+
    foreach (int val in arr) {
+
      sum += val;
+
    }
+

          
+
    double avr = sum / (double)arr.Length;
+

          
+
    // 複数の値をひとまとめにして返したい
+
    return (sum, avr);
+
  }
+

          
+
  static void Main()
+
  {
+
    // 呼び出し側で戻り値を展開したい
+
    (long sum, double avr) = SumAvr(new int[] {2, 5, 3, 8, 4});
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+

          
+
Class Sample
+
  ' 引数で与えられた配列の合計と平均を同時に返すメソッド
+
  Shared Function SumAvr(ByVal arr() As Integer) As (Long, Double)
+

          
+
    Dim sum As Long = 0L
+

          
+
    For Each val As Integer In arr
+
      sum += val
+
    Next
+

          
+
    Dim avr As Double = sum / arr.Length
+

          
+
    ' 複数の値をひとまとめにして返したい
+
    Return (sum, avr)
+

          
+
  End Function
+

          
+
  Shared Sub Main()
+

          
+
    ' 呼び出し側で戻り値を展開したい
+
    (Dim sum As Long, avr As Double) = SumAvr(New Integer() {2, 5, 3, 8, 4})
+

          
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
比較用の参考として、JavaScriptなどいくつかのスクリプト言語では以下のようなコードを記述することができます。
+

          
+
#code(js,type=fragment){{
+
function SumAvr(arr) {
+
  var sum = 0;
+

          
+
  for (var i = 0; i < arr.length; i++) {
+
    sum += arr[i];
+
  }
+

          
+
  var avr = sum / arr.length;
+

          
+
  return [sum, avr];
+
}
+

          
+
var sum, avr;
+

          
+
[sum, avr] = SumAvr([2, 5, 3, 8, 4]);
+
}}
 

        

        
 

        

        
 
#navi(..)
#navi(..)