1

次のような変数を定義するとします。

var o = new { RBI = 108, Name = "Roberto Alamar" };

私は次のようなことができます:

Console.WriteLine("{0}", o);

しかし、私が試してみると:

foreach (var i in o) {
    Console.WriteLine("{0}", o[i]);
}

エラーが発生します:

foreach statement cannot operate on variables of type 'AnonymousType#1' because 'AnonymousType#1' does not contain a public definition for 'GetEnumerator'

では、内部ではどのように機能するのでしょうか。オブジェクトを文字列に変換するメソッドは、タスクを実行するためにすべてのプロパティをループする必要があると思います。これを可能にする特別な方法はありますか、それともこれがどのように機能するか誤解していますか?

4

4 に答える 4

9

内部ではどのように機能しますか?オブジェクトを文字列に変換するメソッドは、タスクを実行するためにすべてのプロパティをループする必要があると思います。

ToStringの実装は、すべての匿名タイプのすべてのインスタンス間で共有されると想定しています。たとえば、JavaScriptで行うのと論理的に同じようなヘルパーがいくつかあります。

var s = "";
for (property in this)
   s += property + ":" + this[property];

この仮定は間違っています。匿名型用のToStringの単一の万能の実装はありません。むしろ、コンパイラは匿名メソッドのすべてのプロパティが何であるかを知っているので、すべての個別の匿名タイプに対してToStringのまったく新しいカスタム実装を生成します。

C#では、ループはJavaScriptでforeachのループのようには機能しません。for-inC#ループは、コレクションのメンバーを列挙します。JSループは、オブジェクトのプロパティを列挙します。

C#でオブジェクトのプロパティを列挙したい場合は、それを行うことができます。もう少し作業が必要です。

var s = "";
foreach (PropertyInfo propertyInfo in this.GetType().GetProperties())
   s += propertyInfo.Name + ":" + propertyInfo.GetValue(this).ToString();
于 2012-04-25T15:07:46.120 に答える
3

匿名型はIEnumerableインターフェイスを実装していないため、これを行うことはできません。これは、1つのオブジェクトだけのコレクションではありません。値を明示的に出力する必要があります。

Console.WriteLine("{0}", o.RBI);
Console.WriteLine("{0}", o.Name);

しかし、一歩下がってください。匿名タイプが必要ですか?独自のカスタムタイプを定義します。

class MyType // give it more meaningful name 
{
     public int RBI { get; set;}
     public string Name { get; set;}
}
于 2012-04-25T02:12:43.130 に答える
2

すべての匿名オブジェクトには同じメソッドがあります。それらは、同じタイプの同じ名前のフィールドを持っている限り、互いに比較することができます。それらはすべて、ToString()あなたが見ることができるように文字列を与える実装を持っています。ただし、列挙子の実装はありません。なぜ彼らはすべきですか?その意味で、プロパティ名/インデックスなどを列挙できるJavascriptとは異なります。なぜなら、それはC#であり、それがそうではないからです。なぜ違うと思いますか?

同様に機能するものが必要な場合は、幸いなことに、変数とリフレクションを暗黙的に型指定して、そこで役立つようにしています。

var obj = new { Foo = "asd", Bar = "add", Gar = "123" };
var adapter = PropertyAdapter.Create(obj);
foreach (var name in adapter)
    Console.WriteLine("obj.{0} = {1}", name, adapter[name]);
public static class PropertyAdapter
{
    public static PropertyAdapter<T> Create<T>(T obj)
    {
        return new PropertyAdapter<T>(obj);
    }
}

public class PropertyAdapter<T> : IEnumerable<string>
{
    private T obj;
    public PropertyAdapter(T obj) { this.obj = obj; }

    public override string ToString()
    {
        return obj.ToString();
    }

    public object this[string name]
    {
        get
        {
            return typeof(T).GetProperty(name).GetValue(obj, null);
        }
    }

    public IEnumerator<string> GetEnumerator()
    {
        return typeof(T)
            .GetProperties()
            .Select(pi => pi.Name)
            .GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}
于 2012-04-25T02:11:34.817 に答える
-1

あなたがするとき

Console.WriteLine("{0}", o);

実際に起こっているのはObject.ToString()の呼び出しです。これは継承され、プロパティと値を出力する匿名型の実装が組み込まれています。

一方で、

foreach (var i in o) { .. }

oIEnumerable(またはIEnumerable <>)である必要があるため、機能しません

編集:使用時に印刷される文字列を列挙することは、次のようにすることで(説明目的で、または他の方法では役に立たない)達成できることと同等です。WriteLine

foreach (var i in o.ToString()) { .. }

ただし、Jeff Mercadoが指摘しているように、それはあなたが望んでいるようには見えません(プロパティを反復処理せず、すでにフォーマットされた文字列の個々の文字のみを反復処理します)

于 2012-04-25T02:12:23.380 に答える