匿名型
匿名型を使用すると、あらかじめ明示的に型を定義することなく、一連の読み取り専用プロパティを単一のオブジェクトにカプセル化できるので便利です。 型の名前はコンパイラにより生成され、ソース コード レベルでは使用できません。 各プロパティの型はコンパイラにより推測されます。
匿名型を作成するには、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
には、 Color
プロパティと Price
プロパティと、関心のないその他のプロパティが含まれます。
class Product
{
public string? Color {get;set;}
public decimal Price {get;set;}
public string? Name {get;set;}
public string? Category {get;set;}
public string? Size {get;set;}
}
匿名型の宣言は、new
キーワードで始まります。 この宣言により、Product
の 2 つのプロパティだけを使用する新しい型が初期化されます。 匿名型を使用すると、クエリに返されるデータの量が少なくなります。
匿名型のメンバー名を指定しない場合、コンパイラは初期化に使用されるプロパティと同じ名前を匿名型メンバーに付けます。 前の例で示されているように、式を使用して初期化されるプロパティの名前を指定します。 次の例では、Color
と Price
が匿名型のプロパティの名前になっています。 インスタンスは、Product
型のproducts
コレクションの項目です。
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 つの匿名型を作成しています。 どちらの場合も、匿名型shipment
とshipmentWithBonus
のproduct
フィールドは、各フィールドの既定値を含む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 }"
.NET