web-dev-qa-db-ja.com

C#匿名タイプの操作

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に関して非常に興味深いことを学びました!

26
Lorenzo

匿名型のリストを返すことはできません。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
汚れた反射を使用します。

35
Greg
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を返すことはできません)、匿名型に名前を付けることはできないため、匿名型を返すことはできません。渡す場合は、匿名でない型を作成する必要があります。実際には、クエリ内を除いて、匿名タイプはあまり使用しないでください。

4
Andrey

このような方法がある場合:

  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の動的変数は、これを解決するための最良の方法です。

2
Jordão

匿名タイプではこれを行うことはできません。 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 );
}

編集:質問の本質的な部分を見逃しました。修正されました。
編集:回答をもう一度変更しました。上記を参照。

1
Mike Webb

リストバック

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;
}
0
Usman Nadeem

私はパーティーに遅れていることを知っていますが、私は何か他のものを研究していて、これを見つけました 記事 あなたの質問に答えます。

オブジェクトのリストを匿名型にキャストして戻すことができます。

    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;
    }
0
mashrur

コンストラクトごとにオブジェクトをvarinに置き換えると機能する場合があります

0
TalentTuner