如何检查c#中动态匿名类型上是否存在属性?


121

我有一个匿名类型对象,该对象是我想从方法中获取的动态方法接收的,该对象存在该属性。

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

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

我将如何实现IsSettingExist?



如果您发现自己严重依赖动态对象,那么可能值得一看F#-Nice Avatar
Piotr Kula

Answers:


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

2
这不适用于动态对象。它始终返回null。
evilom

@evilom @Shikasta_Kashti您是否正在尝试将此方法与MVC一起使用ViewBag?如果是这样,请参阅stackoverflow.com/a/24192518/70345
伊恩·肯普

7
真正的问题:为什么是IsPropertyExist而不是DidPropertyExist / HasProperty?这是我不理解的约定吗?
加斯帕79年

@ Gaspa79。这是一种不常见的编码约定。有些人喜欢所有布尔属性的“ Is”前缀。这样的一致性可以避免您不得不猜测标识符的前几个字符(之后,Intellisense便可以使用),但是在这种情况下,以使英语变得笨拙为代价。
可溶鱼

我发现Is前缀的无效动词时态比其他方式更容易混淆HasProperty。我还要说的是,在C♯中使用这样的语法错误的前缀实际上是不习惯的。
Ben Collins

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 17-4-4

3
objType.GetProperty(name) != null将始终返回a bool(根据定义)永远不会null
亚历克斯·麦克米伦

@AlexMcMillan不知道您Type.GetProperty(string)不存在的属性所处的维度将返回null以外的任何值。
伊恩·坎普

2
@ IanKemp,AlexMcMillan说,objType.GetProperty(name)!= null实际上是在回复MatasVaitkevicius的评论。
谢尔盖(Sergey)

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 '03年

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语句。 ”
rr789 '19

也为我工作。精彩的回答塞思·里诺。我还添加了“如果(obj是Newtonsoft.Json.Linq.JObject)返回(((Newtonsoft.Json.Linq.JObject)obj).ContainsKey(name);”)在以上功能中,由rr789建议。因此,还请编辑您的答案以包括它。
Brijesh Kumar Tripathi

4

这为我工作-

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

               return false;
           }

       }

13
允许发生异常然后捕获它们不是首选的解决方案,因为与抛出和捕获相关的开销很大。这只是万不得已。异常是为在执行过程中不应发生的情况(如网络不可用)而设计的。这里有更好的解决方案。
随便哪个男人

有失败RuntimeBinderExceptiondynamicObj[property].Value 当值确实存在...... var value = dynamicObj[property]就足够了...而当它不存在KeyNotFoundException Dictionary被抛出...见下文......
麦塔斯Vaitkevicius

在业务逻辑中使用异常是不可接受的解决方案。一年级,第二学期。
Artem G

3

上面的解决方案都不dynamic是来自于该解决方案Json,但是我设法Try catch通过将抛出的异常类型(KeyNotFoundException而不是RuntimeBinderException)更改为实际起作用的东西(由@ user3359453转换)。

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

在此处输入图片说明

希望这可以节省您一些时间。


1
不建议在此类情况下使用异常。应该进行诸如强制转换为JObject并使用.Property()!= null之类的
事情

3

合并和修复来自Serj-TM和user3359453的答案,以便它与ExpandoObject和DynamicJsonObject一起使用。这对我有用。

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")){
    // ...
}

1
GetProperties()不在DynamicObject上列出动态成员。为此有一个专用的函数GetDynamicMemberNames()。
Marco Guignard '18年

首先使用lambda表达式Where,然后再使用Any是多余的,因为您也可以使用它来表达过滤表达式Any
pholpar

1

如果有人需要处理来自Json的动态对象,我修改了Seth Reno的答案以处理从NewtonSoft.Json.JObjcet反序列化的动态对象。

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;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.