匿名型

匿名型を使用すると、あらかじめ明示的に型を定義することなく、一連の読み取り専用プロパティを単一のオブジェクトにカプセル化できるので便利です。 型の名前はコンパイラにより生成され、ソース コード レベルでは使用できません。 各プロパティの型はコンパイラにより推測されます。

匿名型を作成するには、new 演算子をオブジェクト初期化子と一緒に使用します。 オブジェクト初期化子の詳細については、「オブジェクト初期化子とコレクション初期化子」を参照してください。

次の例では、Amount および Message という名前の 2 つのプロパティがある、初期化される匿名型を示します。

var v = new { Amount = 108, Message = "Hello" };

// Rest the mouse pointer over v.Amount and v.Message in the following
// statement to verify that their inferred types are int and string.
Console.WriteLine(v.Amount + v.Message);

通常、匿名型はクエリ式の select 句で使用され、ソース シーケンスの各オブジェクトからプロパティのサブセットを返します。 クエリの詳細については、「C# での LINQ」を参照してください。

匿名型には、読み取り専用パブリック プロパティが 1 つ以上含まれます。 それ以外のクラス メンバー (メソッドやイベントなど) は無効です。 プロパティの初期化に使用される式に、null、匿名関数、ポインター型を指定することはできません。

最も一般的な用例は、別の型のプロパティを使用して匿名型を初期化することです。 次の例では、Product という名前のクラスが存在すると仮定します。 Product クラスには、さまざまなプロパティが含まれますが、ここで注目するのは ColorPrice プロパティです。 変数 products は、Product オブジェクトのコレクションです。 匿名型の宣言は、new キーワードで始まります。 この宣言により、Product の 2 つのプロパティだけを使用する新しい型が初期化されます。 匿名型を使用すると、クエリに返されるデータの量が少なくなります。

匿名型のメンバー名を指定しない場合、コンパイラは初期化に使用されるプロパティと同じ名前を匿名型メンバーに付けます。 前の例で示されているように、式を使用して初期化されるプロパティの名前を指定します。 次の例では、ColorPrice が匿名型のプロパティの名前になっています。

var productQuery =
    from prod in products
    select new { prod.Color, prod.Price };

foreach (var v in productQuery)
{
    Console.WriteLine("Color={0}, Price={1}", v.Color, v.Price);
}

ヒント

.NET スタイル規則 IDE0037 を使用し、推論されたメンバー名と明示的なメンバー名のどちらを優先するか強制できます。

別の型のオブジェクトでフィールドを定義することもできます。すなわち、クラスや構造体、または別の匿名型を使うこともできます。 これは、次の例のように、そのオブジェクトを保持する変数を使って実現します。この例では、既にインスタンス化されているユーザー定義型を使って、2 つの匿名型を作成しています。 どちらの場合も、匿名型 shipmentshipmentWithBonusproduct フィールドは、各フィールドの既定値を含む Product 型になります。 また、bonus フィールドは、コンパイラによって作成される匿名型になります。

var product = new Product();
var bonus = new { note = "You won!" };
var shipment = new { address = "Nowhere St.", product };
var shipmentWithBonus = new { address = "Somewhere St.", product, bonus };

通常、変数の初期化に匿名型を使用する場合は、var を使用することにより、変数を暗黙的に型指定したローカル変数として宣言します。 コンパイラだけが匿名型の基になる名前にアクセスできるため、変数宣言では型の名前を指定できません。 var の詳細については、「暗黙的に型指定されたローカル変数」を参照してください。

次の例に示すように、暗黙的に型指定されたローカル変数と暗黙的に型指定された配列を組み合わせることにより、匿名型の要素の配列を作成できます。

var anonArray = new[] { new { name = "apple", diam = 4 }, new { name = "grape", diam = 1 }};

匿名型は object から直接派生した class 型であり、object 以外の型にキャストできません。 コンパイラは各匿名型に名前を付けますが、この名前にアプリケーションはアクセスできません。 共通言語ランタイムから見た場合、匿名型と他の参照型に違いはありません。

アセンブリ内の複数の匿名オブジェクト初期化子が、同じ順序で同じ名前や型を持つプロパティのシーケンスを指定する場合、コンパイラはそれらのオブジェクトを同じ型のインスタンスとして処理します。 これらのオブジェクトは、コンパイラで生成された同一の型情報を共有します。

匿名型では、with 式の形式で非破壊な変化がサポートされます。 これにより、1 つまたは複数のプロパティに新しい値が含まれる匿名型の新しいインスタンスを作成できます。

var apple = new { Item = "apples", Price = 1.35 };
var onSale = apple with { Price = 0.79 };
Console.WriteLine(apple);
Console.WriteLine(onSale);

フィールド、プロパティ、イベント、またはメソッドの戻り値の型は、匿名型を持つものとして宣言できません。 同様に、メソッドの仮パラメーター、プロパティ、コンストラクター、またはインデクサーも、匿名型を持つものとして宣言できません。 匿名型または匿名型を含むコレクションをメソッドの引数として渡すため、パラメーターを object 型として宣言できます。 ただし、匿名型に object を使用すると、強力な型指定の目的が無効になります。 クエリ結果をメソッドの境界を越えて格納したり渡したりする必要がある場合、匿名型の代わりに、通常の名前の構造体またはクラスの使用を検討してください。

匿名型の Equals メソッドと GetHashCode メソッドは、プロパティの Equals メソッドと GetHashCode メソッドとして定義されています。このため、同じ匿名型の 2 つのインスタンスは、すべてのプロパティが等しい場合のみ等しいとみなされます。

Note

匿名型のアクセシビリティ レベルinternal であるため、異なるアセンブリ内で定義されている 2 つの匿名型は同じ型ではありません。 したがって、匿名型のインスタンスは、異なるアセンブリ内で定義されている場合、持っているプロパティがすべて等しい場合でも、互いに等しくありません。

匿名型は ToString メソッドをオーバーライドし、中かっこで囲まれたすべてのプロパティの名前と ToString 出力を連結します。

var v = new { Title = "Hello", Age = 24 };

Console.WriteLine(v.ToString()); // "{ Title = Hello, Age = 24 }"