C#匿名型オブジェクトを含むList変数を返すメソッドを呼び出しています。例えば:
List<object> list = new List<object>();
foreach ( Contact c in allContacts ) {
list.Add( new {
ContactID = c.ContactID,
FullName = c.FullName
});
}
return list;
たとえば、作業中のコードでこのタイプのプロパティを参照するにはどうすればよいですか?
foreach ( object o in list ) {
Console.WriteLine( o.ContactID );
}
私のサンプルは不可能であることを私は知っています、私は匿名タイプの各プロパティを正確に識別する必要があると言うためにそのように書いただけです。
ありがとう!
解決策:
答えの1つだけが正しい、および/または実用的な解決策を提案するだけではありません。グレッグアンサーのオプション3を使用することになりました。そして、.NET4.0のdynamic
に関して非常に興味深いことを学びました!
匿名型のリストを返すことはできません。object
のリストである必要があります。したがって、タイプ情報が失われます。
オプション1
匿名型を使用しないでください。複数のメソッドで匿名型を使用しようとしている場合は、実際のクラスを作成してください。
オプション2
匿名型をobject
にダウンキャストしないでください。 (1つの方法である必要があります)
var list = allContacts
.Select(c => new { c.ContactID, c.FullName })
.ToList();
foreach (var o in list) {
Console.WriteLine(o.ContactID);
}
オプション
dynamicキーワードを使用します。 (.NET 4が必要)
foreach (dynamic o in list) {
Console.WriteLine(o.ContactID);
}
オプション4
汚れた反射を使用します。
foreach ( var o in list ) {
Console.WriteLine( o.ContactID );
}
これは、次のように、リストがIEnumerable<anonymous type>
の場合にのみ機能します。
var list = allContacts.Select(c => new {
ContactID = c.ContactID,
FullName = c.FullName
});
}
ただし、戻り値の型を定義する必要があり(var
を返すことはできません)、匿名型に名前を付けることはできないため、匿名型を返すことはできません。渡す場合は、匿名でない型を作成する必要があります。実際には、クエリ内を除いて、匿名タイプはあまり使用しないでください。
このような方法がある場合:
List<object> GetContactInfo() {
List<object> list = new List<object>();
foreach ( Contact c in allContacts ) {
list.Add( new {
ContactID = c.ContactID,
FullName = c.FullName
});
}
return list;
}
実際にこれを行うべきではありませんが、使用できる 非常に醜く、将来性がない テクニックがあります。
static T CastByExample<T>(object target, T example) {
return (T)target;
}
// .....
var example = new { ContactID = 0, FullName = "" };
foreach (var o in GetContactInfo()) {
var c = CastByExample(o, example);
Console.WriteLine(c.ContactID);
}
これは、コンパイラが同じ「形状」を持つ型(プロパティ名と型)に匿名型を再利用するという事実(変更される可能性があります!)に依存しています。 「例」はメソッド内の型の「形状」と一致するため、同じ型が再利用されます。
ただし、C#4の動的変数は、これを解決するための最良の方法です。
匿名タイプではこれを行うことはできません。 Contactクラス/構造体を作成して使用するだけです。
List<object> list = new List<object>();
foreach ( Contact c in allContacts ) {
list.Add( c );
}
次に、これを行うことができます:
foreach ( var o in list ) {
Console.WriteLine( o.ContactID );
}
...またはこれ:
foreach ( object o in list ) {
Console.WriteLine( ((Contact)o).ContactID ); //Gives intellisense
}
もちろん、その場合は、オブジェクトリストの代わりに連絡先リストを作成する必要があります。
List<Contact> list = new List<Contact>();
foreach ( Contact c in allContacts ) {
list.Add( c );
}
編集:質問の本質的な部分を見逃しました。修正されました。
編集:回答をもう一度変更しました。上記を参照。
リストバック
public static void Main()
{
foreach (object item in GetList())
{
var x = Cast(item, new { ContactID = 0, FullName = "" });
Console.WriteLine(x.ContactID + " " + x.FullName);
}
}
public static IEnumerable<object> GetList()
{
yield return new { ContactID = 4, FullName = "Jack Smith" };
yield return new { ContactID = 5, FullName = "John Doe" };
}
public static T Cast<T>(object obj, T type)
{
return (T)obj;
}
私はパーティーに遅れていることを知っていますが、私は何か他のものを研究していて、これを見つけました 記事 あなたの質問に答えます。
オブジェクトのリストを匿名型にキャストして戻すことができます。
public static void Main()
{
foreach (object item in GetList())
{
var x = Cast(item, new { ContactID = 0, FullName = "" });
Console.WriteLine(x.ContactID + " " + x.FullName);
}
}
public static IEnumerable<object> GetList()
{
yield return new { ContactID = 4, FullName = "Jack Smith" };
yield return new { ContactID = 5, FullName = "John Doe" };
}
public static T Cast<T>(object obj, T type)
{
return (T)obj;
}
コンストラクトごとにオブジェクトをvarinに置き換えると機能する場合があります