199

javascript では、 undefined キーワードを使用してプロパティが定義されているかどうかを検出できます。

if( typeof data.myProperty == "undefined" ) ...

ExpandoObjectdynamic キーワードを使用し、例外をスローせずに C# でこれを行うにはどうすればよいでしょうか?

4

11 に答える 11

195

MSDNによると、宣言は IDictionary を実装していることを示しています。

public sealed class ExpandoObject : IDynamicMetaObjectProvider, 
    IDictionary<string, Object>, ICollection<KeyValuePair<string, Object>>, 
    IEnumerable<KeyValuePair<string, Object>>, IEnumerable, INotifyPropertyChanged

これを使用して、メンバーが定義されているかどうかを確認できます。

var expandoObject = ...;
if(((IDictionary<String, object>)expandoObject).ContainsKey("SomeMember")) {
    // expandoObject.SomeMember exists.
}
于 2010-05-15T09:33:05.157 に答える
32

ここで重要な区別をする必要があります。

ここでの回答のほとんどは、質問で言及されている ExpandoObject に固有のものです。しかし、一般的な使用法 (および検索時にこの質問にたどり着く理由) は、ASP.Net MVC ViewBag を使用する場合です。これは DynamicObject のカスタム実装/サブクラスであり、null の任意のプロパティ名をチェックしても例外をスローしません。次のようなプロパティを宣言するとします。

@{
    ViewBag.EnableThinger = true;
}

次に、その値をチェックし、それが設定されているかどうか、つまり存在するかどうかを確認したいとします。以下は有効で、コンパイルされ、例外をスローせず、正しい答えが得られます。

if (ViewBag.EnableThinger != null && ViewBag.EnableThinger)
{
    // Do some stuff when EnableThinger is true
}

EnableThinger の宣言を削除します。同じコードが正しくコンパイルおよび実行されます。反省はいらない。

ViewBag とは異なり、存在しないプロパティで null をチェックすると、ExpandoObject がスローされます。MVC ViewBag のより穏やかな機能をdynamicオブジェクトから引き出すには、スローしない dynamic の実装を使用する必要があります。

MVC ViewBag で正確な実装を使用するだけです。

. . .
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
    result = ViewData[binder.Name];
    // since ViewDataDictionary always returns a result even if the key does not exist, always return true
    return true;
}
. . .

https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Mvc/DynamicViewDataDictionary.cs

MVC ViewPage で、MVC ビューに関連付けられていることがわかります。

http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/ViewPage.cs

DynamicViewDataDictionary の優雅な動作の鍵は、ViewDataDictionary の Dictionary 実装です。

public object this[string key]
{
    get
    {
        object value;
        _innerDictionary.TryGetValue(key, out value);
        return value;
    }
    set { _innerDictionary[key] = value; }
}

https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Mvc/ViewDataDictionary.cs

つまり、キーの内容に関係なく、常にすべてのキーの値を返します。何もない場合は単に null を返します。ただし、ViewDataDictionary は MVC のモデルに結び付けられるという負担があるため、MVC ビューの外で使用するために適切なディクショナリ部分だけを削除することをお勧めします。

ここにすべての内臓を実際に投稿するには長すぎます-ほとんどは IDictionary を実装するだけです-しかしDDict、Github で、宣言されていないプロパティの null チェックをスローしない動的オブジェクト ( class ) を次に示します。

https://github.com/b9chris/GracefulDynamicDictionary

NuGet を介してプロジェクトに追加するだけの場合、その名前はGracefulDynamicDictionaryです。

于 2014-06-12T19:30:32.737 に答える
15

次のようなことができるように、拡張メソッドを作成したかったのです。

dynamic myDynamicObject;
myDynamicObject.propertyName = "value";

if (myDynamicObject.HasProperty("propertyName"))
{
    //...
}

ExpandoObject...しかし、C# 5 のドキュメント (詳細はこちら)によると、拡張機能を作成することはできません。

だから私はクラスヘルパーを作成することになりました:

public static class ExpandoObjectHelper
{
    public static bool HasProperty(ExpandoObject obj, string propertyName)
    {
        return obj != null && ((IDictionary<String, object>)obj).ContainsKey(propertyName);
    }
}

使用するには:

// If the 'MyProperty' property exists...
if (ExpandoObjectHelper.HasProperty(obj, "MyProperty"))
{
    ...
}
于 2016-12-09T15:14:41.143 に答える
12

更新: デリゲートを使用して、存在する場合は動的オブジェクト プロパティから値を取得しようとすることができます。プロパティがない場合は、単純に例外をキャッチして false を返します。

見てください、それは私にとってはうまくいきます:

class Program
{
    static void Main(string[] args)
    {
        dynamic userDynamic = new JsonUser();

        Console.WriteLine(IsPropertyExist(() => userDynamic.first_name));
        Console.WriteLine(IsPropertyExist(() => userDynamic.address));
        Console.WriteLine(IsPropertyExist(() => userDynamic.last_name));
    }

    class JsonUser
    {
        public string first_name { get; set; }
        public string address
        {
            get
            {
                throw new InvalidOperationException("Cannot read property value");
            }
        }
    }

    static bool IsPropertyExist(GetValueDelegate getValueMethod)
    {
        try
        {
            //we're not interesting in the return value. What we need to know is whether an exception occurred or not
            getValueMethod();
            return true;
        }
        catch (RuntimeBinderException)
        {
            // RuntimeBinderException occurred during accessing the property
            // and it means there is no such property         
            return false;
        }
        catch
        {
            //property exists, but an exception occurred during getting of a value
            return true;
        }
    }

    delegate string GetValueDelegate();
}

コードの出力は次のとおりです。

True
True
False
于 2012-09-18T20:51:10.453 に答える
11

最近、非常によく似た質問に答えました。動的オブジェクトのメンバーを反映​​するにはどうすればよいですか?

まもなく、取得できる動的オブジェクトは ExpandoObject だけではありません。リフレクションは、静的型 (IDynamicMetaObjectProvider を実装しない型) に対して機能します。このインターフェイスを実装する型の場合、リフレクションは基本的に役に立ちません。ExpandoObject の場合、プロパティが基になるディクショナリでキーとして定義されているかどうかを簡単に確認できます。他の実装の場合、それは困難な場合があり、例外を処理することが唯一の方法である場合があります。詳細については、上記のリンクをたどってください。

于 2010-05-17T06:34:05.493 に答える
1

リフレクションを使用して型プロパティのセットを取得したくないのはなぜですか? このような

 dynamic v = new Foo();
 Type t = v.GetType();
 System.Reflection.PropertyInfo[] pInfo =  t.GetProperties();
 if (Array.Find<System.Reflection.PropertyInfo>(pInfo, p => { return p.Name == "PropName"; }).    GetValue(v,  null) != null))
 {
     //PropName initialized
 } 
于 2010-05-15T10:12:24.297 に答える
1

ユース ケースに応じて、null を未定義と同じと見なすことができる場合は、ExpandoObject を DynamicJsonObject に変換できます。

    dynamic x = new System.Web.Helpers.DynamicJsonObject(new ExpandoObject());
    x.a = 1;
    x.b = 2.50;
    Console.WriteLine("a is " + (x.a ?? "undefined"));
    Console.WriteLine("b is " + (x.b ?? "undefined"));
    Console.WriteLine("c is " + (x.c ?? "undefined"));

出力:

a is 1
b is 2.5
c is undefined
于 2019-09-27T07:18:42.950 に答える
-2
(authorDynamic as ExpandoObject).Any(pair => pair.Key == "YourProp");
于 2015-11-21T18:33:38.283 に答える
-3

CPU サイクルを大量に消費するすべてのものに Reflection を使用するのをやめてください。

解決策は次のとおりです。

public class DynamicDictionary : DynamicObject
{
    Dictionary<string, object> dictionary = new Dictionary<string, object>();

    public int Count
    {
        get
        {
            return dictionary.Count;
        }
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        string name = binder.Name;

        if (!dictionary.TryGetValue(binder.Name, out result))
            result = "undefined";

        return true;
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        dictionary[binder.Name] = value;
        return true;
    }
}
于 2010-05-15T15:43:29.093 に答える
-6

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

public bool PropertyExist(object obj, string propertyName)
{
 return obj.GetType().GetProperty(propertyName) != null;
}
于 2012-07-18T12:01:20.247 に答える