c#で動的匿名型にプロパティが存在するかどうかを確認するにはどうすればよいですか?


122

プロパティからチェックインしたいメソッドから動的として受け取る匿名タイプのオブジェクトがそのオブジェクトに存在します。

....
var settings = new {
                   Filename="temp.txt",
                   Size=10
}
...

function void Settings(dynamic settings) {
var exists = IsSettingExist(settings,"Filename")
}

IsSettingExistはどのように実装しますか?



動的オブジェクトに大きく依存している自分を見つけた場合は、おそらくF#を見てみる価値があります
Piotr Kula

回答:


149
  public static bool IsPropertyExist(dynamic settings, string name)
  {
    if (settings is ExpandoObject)
      return ((IDictionary<string, object>)settings).ContainsKey(name);

    return settings.GetType().GetProperty(name) != null;
  }

  var settings = new {Filename = @"c:\temp\q.txt"};
  Console.WriteLine(IsPropertyExist(settings, "Filename"));
  Console.WriteLine(IsPropertyExist(settings, "Size"));

出力:

 True
 False

3
これは動的オブジェクトでは機能しません。常にnullを返します。
evilom

@evilom @Shikasta_KashtiこのメソッドをMVCで使用しようとしていますViewBagか?その場合は、stackoverflow.com
Ian Kemp

@ Gaspa79。これは珍しいコーディング規約ではありません。すべてのブールプロパティの "Is"プレフィックスを好む人もいます。このような一貫性があると、識別子の最初の数文字を推測する必要がなくなります(その後、Intellisenseが機能します)。
可溶性魚

Is接頭辞の無効な動詞時制は、他の方法で使用する場合よりも混乱しますHasProperty。このように文法的に正しくない接頭辞を使用することは、C♯では実際には非慣用的であるとも言えます。
ベンコリンズ

ExpandoObjectは、匿名型と同じものではありません。私はそれについて間違っていますか?
ryanwebjackson

37
public static bool HasProperty(dynamic obj, string name)
{
    Type objType = obj.GetType();

    if (objType == typeof(ExpandoObject))
    {
        return ((IDictionary<string, object>)obj).ContainsKey(name);
    }

    return objType.GetProperty(name) != null;
}

objType.GetProperty(name) != null;存在するプロパティではnullを返します
Matas Vaitkevicius 2017

3
objType.GetProperty(name) != nullは常にを返しますがbool、これは(定義上)決してではありませんnull
Alex McMillan

@AlexMcMillan Type.GetProperty(string)存在しないプロパティのどこに住んでいるかがわからない場合、null以外の値が返されます。
Ian Kemp

2
@ IanKemp、AlexMcMillanは、実際にMatasVaitkeviciusのコメントに応えて、objType.GetProperty (name)!= nullと言っています
セルゲイ

15

設定オブジェクトの作成/受け渡しを制御できる場合は、代わりにExpandoObjectを使用することをお勧めします。

dynamic settings = new ExpandoObject();
settings.Filename = "asdf.txt";
settings.Size = 10;
...

function void Settings(dynamic settings)
{
    if ( ((IDictionary<string, object>)settings).ContainsKey("Filename") )
        .... do something ....
}

変更できません。ExpendoObjectにキャストできますか?
David MZ

6

匿名型、のためのこれは作品ExpandoObjectNancy.DynamicDictionaryまたはにキャストすることができない何かIDictionary<string, object>

    public static bool PropertyExists(dynamic obj, string name) {
        if (obj == null) return false;
        if (obj is IDictionary<string, object> dict) {
            return dict.ContainsKey(name);
        }
        return obj.GetType().GetProperty(name) != null;
    }

2
素晴らしいソリューション。JSON文字列をJObjectに変換するときに、IFステートメントをもう1つ追加する必要がありました。 」
rr789

1
また私のために働いた。素晴らしい答えセスリノ。また、「if(objがNewtonsoft.Json.Linq.JObject)return((Newtonsoft.Json.Linq.JObject)obj).ContainsKey(name);」を追加しました。上記の関数はrr789で提案されています。回答を編集して、それを含めてください。
Brijesh Kumar Tripathi

1
@BrijeshKumarTripathiありがとうございます!これはまさに私のシナリオでした。
ryanwebjackson

4

これは私のために働いています-:

  public static bool IsPropertyExist(dynamic dynamicObj, string property)
       {
           try
           {
               var value=dynamicObj[property].Value;
               return true;
           }
           catch (RuntimeBinderException)
           {

               return false;
           }

       }

14
例外の発生を許可してからキャッチすることは、スローとキャッチに関連するオーバーヘッドが多いため、推奨されるソリューションではありません。これは最後の手段です。例外は、ネットワークが利用できないなど、実行中に発生してはならない状況向けに設計されています。ここにはもっと良い解決策があります。
Whatever Man

で失敗RuntimeBinderExceptionし、dynamicObj[property].Value 値が実際に存在するとき... var value = dynamicObj[property]十分です...そしてそれが存在しない場合KeyNotFoundException Dictionaryスローされます... ...以下を参照してください
マタスVaitkevicius

ビジネスロジックで例外を使用することは、容認できない解決策です。1学年、2学期。
Artem G

3

以下のために働いていた上記の解決策のいずれdynamicから来てJson、私はしかし、で1を変換するために管理していないTry catch例外スロータイプ(変更することにより、(@ user3359453による)KeyNotFoundExceptionの代わりに、RuntimeBinderException実際に動作するものに)を...

public static bool HasProperty(dynamic obj, string name)
    {
        try
        {
            var value = obj[name];
            return true;
        }
        catch (KeyNotFoundException)
        {
            return false;
        }
    }

ここに画像の説明を入力してください

これにより時間を節約できることを願っています。


1
このようなものに例外を使用することはお勧めしません。JObjectにキャストして.Property()を使用するようなことをしているはずです!= null
Gaspa79

3

ExpandoObjectとDynamicJsonObjectの両方で動作するように、Serj-TMとuser3359453からの回答をマージして修正します。これでうまくいきます。

public static bool HasPropertyExist(dynamic settings, string name)
{
    if (settings is System.Dynamic.ExpandoObject)
        return ((IDictionary<string, object>)settings).ContainsKey(name);

    if (settings is System.Web.Helpers.DynamicJsonObject)
    try
    {
        return settings[name] != null;
    }
    catch (KeyNotFoundException)
    {
        return false;
    }


    return settings.GetType().GetProperty(name) != null;
}

2

リフレクションを使用して、これは私が使用する関数です:

public static bool doesPropertyExist(dynamic obj, string property)
{
    return ((Type)obj.GetType()).GetProperties().Where(p => p.Name.Equals(property)).Any();
}

それから

if (doesPropertyExist(myDynamicObject, "myProperty")){
    // ...
}

2
GetProperties()は、DynamicObjectの動的メンバーをリストしません。そのための専用の関数GetDynamicMemberNames()があります。
マルコギニャール2018

Where最初にラムダ式を使用し、次にAnyフィルタリング式を作成することもできるため、冗長ですAny
ホルパー

1

動的オブジェクトを処理する必要がある人がJsonから来た場合に備えて、NewtonSoft.Json.JObjcetから逆シリアル化された動的オブジェクトを処理するようにSeth Renoの回答を変更しました。

public static bool PropertyExists(dynamic obj, string name)
    {
        if (obj == null) return false;
        if (obj is ExpandoObject)
            return ((IDictionary<string, object>)obj).ContainsKey(name);
        if (obj is IDictionary<string, object> dict1)
            return dict1.ContainsKey(name);
        if (obj is IDictionary<string, JToken> dict2)
            return dict2.ContainsKey(name);
        return obj.GetType().GetProperty(name) != null;
    }

0

@Kuroroからの回答を拡張するには、プロパティが空であるかどうかをテストする必要がある場合、以下が機能するはずです。

public static bool PropertyExistsAndIsNotNull(dynamic obj, string name)
{
    if (obj == null) return false;
    if (obj is ExpandoObject)
    {
        if (((IDictionary<string, object>)obj).ContainsKey(name))
            return ((IDictionary<string, object>)obj)[name] != null;
        return false;
    }
    if (obj is IDictionary<string, object> dict1)
    {
        if (dict1.ContainsKey(name))
            return dict1[name] != null;
        return false;
    }
    if (obj is IDictionary<string, JToken> dict2)
    {
        if (dict2.ContainsKey(name))
            return (dict2[name].Type != JTokenType.Null && dict2[name].Type != JTokenType.Undefined);
        return false;
    }
    if (obj.GetType().GetProperty(name) != null)
        return obj.GetType().GetProperty(name).GetValue(obj) != null;
    return false;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.