c#foreach(オブジェクトのプロパティ)…これを行う簡単な方法はありますか?


92

私はいくつかのプロパティを含むクラスを持っています(違いがある場合、すべて文字列です)。
また、クラスの多くの異なるインスタンスを含むリストもあります。

クラスの単体テストを作成しているときに、リスト内の各オブジェクトをループし、そのオブジェクトの各プロパティをループすることを決めました...

これを行うのは簡単だと思いました...

foreach (Object obj in theList)
{
     foreach (Property theProperties in obj)
     {
         do some stufff!!;
     }
}

しかし、これはうまくいきませんでした!:(私はこのエラーを受け取ります...

"foreachステートメントは、 'Application.Object'に 'GetEnumerator'のパブリック定義が含まれていないため、タイプ 'Application.Object'の変数を操作できません。

誰もが大量のifsやループなしで、またはあまりにも複雑なことをせずにこれを行う方法を知っていますか?


5
今後、質問で「うまくいかない」と言わないでください。代わりに、発生している問題(コンパイラエラーなど)を指定してください。ありがとう!
Robert Harvey

2
更新しました!ロバートのご
協力

回答:


143

これを試してみてください:

foreach (PropertyInfo propertyInfo in obj.GetType().GetProperties())
{
   // do stuff here
}

またType.GetProperties()、バインディングフラグのセットを受け入れるオーバーロードがあるため、アクセシビリティレベルなどの異なる基準でプロパティをフィルターで除外できることに注意してください。詳細については、MSDNを参照してください:Type.GetPropertiesメソッド(BindingFlags)最後に、忘れずに「system.Reflection」アセンブリ参照を追加します。

たとえば、すべてのパブリックプロパティを解決するには:

foreach (var propertyInfo in obj.GetType()
                                .GetProperties(
                                        BindingFlags.Public 
                                        | BindingFlags.Instance))
{
   // do stuff here
}

これが期待どおりに機能するかどうかをお知らせください。


4
オブジェクトプロパティのハンドルを取得したら、各プロパティの値を取得する方法はありますか?例:名前または郵便番号
JsonStatham

35

次のように、オブジェクトのすべての非インデックスプロパティをループできます。

var s = new MyObject();
foreach (var p in s.GetType().GetProperties().Where(p => !p.GetGetMethod().GetParameters().Any())) {
    Console.WriteLine(p.GetValue(s, null));
}

GetProperties()は単純なプロパティだけでなくインデクサーも返すため、呼び出す前に追加のフィルターが必要であり、2番目のパラメーターとしてGetValue渡すことが安全であることを認識しnullます。

書き込み専用などのアクセスできないプロパティを除外するために、フィルターをさらに変更する必要がある場合があります。


+1は、実際に使用できるプロパティで何かを行う場合にのみ使用します。書き込み専用プロパティを除外することもできます。

@hvd書き込み専用プロパティの優れた点です。私はそれらについてほとんど忘れてしまいました。nullgetterのあるプロパティに遭遇するとコードがクラッシュしますが、OPが必要なプロパティのみを取得する方法をOPが理解できると確信しています。
dasblinkenlight 2012年

27

あと少しで、コレクションまたはプロパティバッグの形式でプロパティにアクセスできることを期待するのではなく、型からプロパティを取得する必要があります。

var property in obj.GetType().GetProperties()

そこから、次のようにアクセスできます

property.Name
property.GetValue(obj, null)

GetValue2番目のパラメータは、プロパティがコレクションを返すと連携しますインデックス値を指定することができます-文字列は文字の集合であるから、あなたもニーズがあることならば、文字を返すためにインデックスを指定することができます。


1
私は誰かを怒らせましたか?私はこれについて何が悪いのかを知ることにオープンです、さもなければ私は決して学ばないかもしれません。
Grant Thomas

おそらく、コードが間違っているとき(忍者の編集の前)に反対票を獲得しました。
Robert Harvey

20

もちろん問題ありません:

foreach(object item in sequence)
{
    if (item == null) continue;
    foreach(PropertyInfo property in item.GetType().GetProperties())
    {
        // do something with the property
    }
}

なぜこの行を追加したのですか?if (item == null) continue;個人的には、その時点でnullオブジェクトを取得した場合、何かがずっと前に問題が発生し、それが検証が行われるべき場所だと思いますか、それとも私は間違っていますか?
Rafael Herscovici、2016

@Dementic:もちろん、シーケンスにはnull以外の参照を含める必要があると言えます。
Eric Lippert、2016

3

これを行うにはリフレクションを使用します

SomeClass A = SomeClass(...)
PropertyInfo[] properties = A.GetType().GetProperties();

2

私はこのページで同様の質問への回答を探し、このページにアクセスする人々を助けるためにいくつかの同様の質問への回答を書きました。

クラス一覧

List <T>クラスは、インデックスでアクセスできるオブジェクトのリストを表します。これは、System.Collection.Generic名前空間の下にあります。Listクラスは、整数、文字列などのさまざまなタイプのコレクションを作成するために使用できます。Listクラスは、リストを検索、ソート、および操作するメソッドも提供します。

プロパティを持つクラス

class TestClss
{
    public string id { set; get; }
    public string cell1 { set; get; }
    public string cell2 { set; get; }
}
var MyArray = new List<TestClss> {
    new TestClss() { id = "1", cell1 = "cell 1 row 1 Data", cell2 = "cell 2 row 1 Data" },
    new TestClss() { id = "2", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 2 Data" },
    new TestClss() { id = "3", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 3 Data" }
};
foreach (object Item in MyArray)
{
    Console.WriteLine("Row Start");
    foreach (PropertyInfo property in Item.GetType().GetProperties())
    {
        var Key = property.Name;
        var Value = property.GetValue(Item, null);
        Console.WriteLine("{0}={1}", Key, Value);
    }
}

または、フィールドのあるクラス

class TestClss
{
    public string id = "";
    public string cell1 = "";
    public string cell2 = "";
}
var MyArray = new List<TestClss> {
    new TestClss() { id = "1", cell1 = "cell 1 row 1 Data", cell2 = "cell 2 row 1 Data" },
    new TestClss() { id = "2", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 2 Data" },
    new TestClss() { id = "3", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 3 Data" }
};
foreach (object Item in MyArray)
{
    Console.WriteLine("Row Start");
    foreach (var fieldInfo in Item.GetType().GetFields())
    {
        var Key = fieldInfo.Name;
        var Value = fieldInfo.GetValue(Item);
    }

}

または、オブジェクトのリスト(同じセルなし):

var MyArray = new List<object> {
    new { id = "1", cell1 = "cell 1 row 1 Data", cell2 = "cell 2 row 1 Data" },
    new { id = "2", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 2 Data" },
    new { id = "3", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 3 Data", anotherCell = "" }
};
foreach (object Item in MyArray)
{
    Console.WriteLine("Row Start");
    foreach (var props in Item.GetType().GetProperties())
    {
        var Key = props.Name;
        var Value = props.GetMethod.Invoke(Item, null).ToString();
        Console.WriteLine("{0}={1}", Key, Value);
    }
}

または、オブジェクトのリスト(同じセルが必要):

var MyArray = new[] {
    new { id = "1", cell1 = "cell 1 row 1 Data", cell2 = "cell 2 row 1 Data" },
    new { id = "2", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 2 Data" },
    new { id = "3", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 3 Data" }
};
foreach (object Item in MyArray)
{
    Console.WriteLine("Row Start");
    foreach (var props in Item.GetType().GetProperties())
    {
        var Key = props.Name;
        var Value = props.GetMethod.Invoke(Item, null).ToString();
        Console.WriteLine("{0}={1}", Key, Value);
    }
}

または、オブジェクトのリスト(キー付き):

var MyArray = new {
    row1 = new { id = "1", cell1 = "cell 1 row 1 Data", cell2 = "cell 2 row 1 Data" },
    row2 = new { id = "2", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 2 Data" },
    row3 = new { id = "3", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 3 Data" }
};
// using System.ComponentModel;  for TypeDescriptor
foreach (PropertyDescriptor Item in TypeDescriptor.GetProperties(MyArray))
{
    string Rowkey = Item.Name;
    object RowValue = Item.GetValue(MyArray);
    Console.WriteLine("Row key is: {0}", Rowkey);
    foreach (var props in RowValue.GetType().GetProperties())
    {
        var Key = props.Name;
        var Value = props.GetMethod.Invoke(RowValue, null).ToString();
        Console.WriteLine("{0}={1}", Key, Value);
    }
}

または、辞書のリスト

var MyArray = new List<Dictionary<string, string>>() {
    new Dictionary<string, string>() { { "id", "1" }, { "cell1", "cell 1 row 1 Data" }, { "cell2", "cell 2 row 1 Data" } },
    new Dictionary<string, string>() { { "id", "2" }, { "cell1", "cell 1 row 2 Data" }, { "cell2", "cell 2 row 2 Data" } },
    new Dictionary<string, string>() { { "id", "3" }, { "cell1", "cell 1 row 3 Data" }, { "cell2", "cell 2 row 3 Data" } }
};
foreach (Dictionary<string, string> Item in MyArray)
{
    Console.WriteLine("Row Start");
    foreach (KeyValuePair<string, string> props in Item)
    {
        var Key = props.Key;
        var Value = props.Value;
        Console.WriteLine("{0}={1}", Key, Value);
    }
}

幸運を..


0

「何かを行う」とは、アクセスする実際のプロパティの値を更新することを意味し、ルートオブジェクトからアクセスしたプロパティへのパスに構造体タイプのプロパティがある場合、プロパティに加えた変更はルートオブジェクトには反映されません。


0

上記の方法はどれもうまくいきませんでしたが、うまくいきました。DirectoryEntryのユーザー名とパスワードはオプションです。

   private List<string> getAnyDirectoryEntryPropertyValue(string userPrincipalName, string propertyToSearchFor)
    {
        List<string> returnValue = new List<string>();
        try
        {
            int index = userPrincipalName.IndexOf("@");
            string originatingServer = userPrincipalName.Remove(0, index + 1);
            string path = "LDAP://" + originatingServer; //+ @"/" + distinguishedName;
            DirectoryEntry objRootDSE = new DirectoryEntry(path, PSUsername, PSPassword);
            var objSearcher = new System.DirectoryServices.DirectorySearcher(objRootDSE);
            objSearcher.Filter = string.Format("(&(UserPrincipalName={0}))", userPrincipalName);
            SearchResultCollection properties = objSearcher.FindAll();

            ResultPropertyValueCollection resPropertyCollection = properties[0].Properties[propertyToSearchFor];
            foreach (string resProperty in resPropertyCollection)
            {
                returnValue.Add(resProperty);
            }
        }
        catch (Exception ex)
        {
            returnValue.Add(ex.Message);
            throw;
        }

        return returnValue;
    }

0

この質問への以前の回答に主に基づいたコピー/ペーストソリューション(拡張方法)。

また、この反映されたものを処理するときにしばしば必要となるIDicitonary(ExpandoObject / dynamic)を適切に処理します。

タイトなループやその他のホットパスでの使用は推奨されません。これらの場合、キャッシング/ ILエミット/式ツリーのコンパイルが必要になります。

    public static IEnumerable<(string Name, object Value)> GetProperties(this object src)
    {
        if (src is IDictionary<string, object> dictionary)
        {
            return dictionary.Select(x => (x.Key, x.Value));
        }
        return src.GetObjectProperties().Select(x => (x.Name, x.GetValue(src)));
    }

    public static IEnumerable<PropertyInfo> GetObjectProperties(this object src)
    {
        return src.GetType()
            .GetProperties(BindingFlags.Public | BindingFlags.Instance)
            .Where(p => !p.GetGetMethod().GetParameters().Any());
    }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.