如何检查 C# 中的动态匿名类型上是不是存在属性?
Posted
技术标签:
【中文标题】如何检查 C# 中的动态匿名类型上是不是存在属性?【英文标题】:How do I check if a property exists on a dynamic anonymous type in c#?如何检查 C# 中的动态匿名类型上是否存在属性? 【发布时间】:2012-04-14 22:41:53 【问题描述】:我有一个匿名类型对象,我从方法中接收到动态对象 我想检查该对象上是否存在属性。
....
var settings = new
Filename="temp.txt",
Size=10
...
function void Settings(dynamic settings)
var exists = IsSettingExist(settings,"Filename")
我将如何实现 IsSettingExist ?
【问题讨论】:
How to detect if a property exists on an ExpandoObject?的可能重复 如果你发现自己严重依赖动态对象,那么可能值得看看 F# - 顺便说一句,Nice Avatar 【参考方案1】: 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
【讨论】:
这不适用于动态对象。它总是返回 null。 @evilom @Shikasta_Kashti 您是否尝试将此方法与 MVCViewBag
一起使用?如果是这样,请参阅***.com/a/24192518/70345
@Gaspa79。这是一个不常见的编码约定。有些人喜欢在所有布尔属性上加上“Is”前缀。这样的一致性可以防止您不得不猜测标识符的前几个字符(之后,Intellisense 起作用),但代价是在这种情况下会产生一些尴尬的英语。
我发现 Is
前缀的无效动词时态比使用 HasProperty
更令人困惑。我还要说,在 C♯ 中使用这样的语法错误前缀实际上是非惯用的。
ExpandoObject 与匿名类型不同。我错了吗?【参考方案2】:
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
objType.GetProperty(name) != null
将始终返回一个bool
,它(根据定义)永远不可能是null
。
@AlexMcMillan 不确定你住在哪个维度,Type.GetProperty(string)
对于不存在的属性返回 null 以外的任何内容。
@IanKemp,AlexMcMillan 实际上在回复 MatasVaitkevicius 评论时说 objType.GetProperty(name) != null。【参考方案3】:
如果您可以控制创建/传递设置对象,我建议改用 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 吗?【参考方案4】:这适用于匿名类型,ExpandoObject
、Nancy.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;
【讨论】:
很好的解决方案。在将 JSON 字符串转换为 JObject 时,我需要再添加一条 IF 语句......"if (obj is Newtonsoft.Json.Linq.JObject) return ((Newtonsoft.Json.Linq.JObject)obj).ContainsKey(name); " 也为我工作。精彩的回答赛斯雷诺。我还添加了“if (obj is Newtonsoft.Json.Linq.JObject) return ((Newtonsoft.Json.Linq.JObject)obj).ContainsKey(name);”在 rr789 建议的上述功能中。因此,还请编辑您的答案以包含它。 谢谢@BrijeshKumarTripathi!这正是我的场景。【参考方案5】:这对我有用-:
public static bool IsPropertyExist(dynamic dynamicObj, string property)
try
var value=dynamicObj[property].Value;
return true;
catch (RuntimeBinderException)
return false;
【讨论】:
允许异常发生然后捕获它们不是首选的解决方案,因为抛出和捕获相关的开销很大。这只是最后的手段。例外适用于在执行过程中不应该发生的情况,例如网络不可用。这里有更好的解决方案。 当值实际存在时,RuntimeBinderException
和 dynamicObj[property].Value
失败......var value = dynamicObj[property]
就足够了......当它不存在时,KeyNotFoundException
上的 Dictionary
被抛出.. . 见下文...
在业务逻辑中使用异常是不可接受的解决方案。 1 年级,第 2 学期。【参考方案6】:
合并和修复来自 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;
【讨论】:
【参考方案7】:使用反射,这是我使用的功能:
public static bool doesPropertyExist(dynamic obj, string property)
return ((Type)obj.GetType()).GetProperties().Where(p => p.Name.Equals(property)).Any();
那么..
if (doesPropertyExist(myDynamicObject, "myProperty"))
// ...
【讨论】:
GetProperties() 没有列出 DynamicObject 上的动态成员。为此有一个专用函数 GetDynamicMemberNames()。 先使用 lambda 表达式Where
,然后使用 Any
是多余的,因为您也可以在 Any
中制定过滤表达式。【参考方案8】:
我遇到的动态是Newtonsoft.Json.Linq.JObject
而不是IDictionary
如果它有效,我添加了额外的内容。
public static bool PropertyExists(dynamic obj, string name)
if (obj == null) return false;
else if (obj is IDictionary<string, object> dict)
return dict.ContainsKey(name);
else if (obj is Newtonsoft.Json.Linq.JObject jObject)
return jObject.ContainsKey(name);
else
return obj.GetType().GetProperty(name) != null;
【讨论】:
【参考方案9】:上述解决方案均不适用于来自Json
的dynamic
,但是我设法通过更改引发的异常类型(KeyNotFoundException
而不是RuntimeBinderException
)来转换一个带有Try catch
(@user3359453)的解决方案变成真正有效的东西......
public static bool HasProperty(dynamic obj, string name)
try
var value = obj[name];
return true;
catch (KeyNotFoundException)
return false;
希望这可以为您节省一些时间。
【讨论】:
不建议对此类事情使用例外。应该使用诸如转换为 JObject 并使用 .Property() != null 之类的东西【参考方案10】:如果有人需要处理来自 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;
【讨论】:
【参考方案11】:为了扩展@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;
【讨论】:
【参考方案12】:这也适用于 DynamicJsonObject:
public static bool PropertyExists(dynamic settings, string name)
if (settings is ExpandoObject)
return ((IDictionary<string, object>)settings).ContainsKey(name);
else if (settings is DynamicJsonObject)
return ((DynamicJsonObject)settings).GetDynamicMemberNames().Contains(name);
return settings.GetType().GetProperty(name) != null;
【讨论】:
【参考方案13】: public static void Test()
int LOOP_LENGTH = 100000000;
long first_memory = GC.GetTotalMemory(true);
var stopWatch = Stopwatch.StartNew();
Console.WriteLine("doesPropertyExist");
dynamic testdo = new A = 1, B = (string)null, C = "A" ;
for (int i = 0; i < LOOP_LENGTH; i++)
if (!TestDynamic.doesPropertyExist(testdo, "A"))
Console.WriteLine("throw find");
break;
if (TestDynamic.doesPropertyExist(testdo, "ABC"))
Console.WriteLine("throw not find");
break;
stopWatch.Stop();
var last_memory = GC.GetTotalMemory(true);
Console.WriteLine($" Time:stopWatch.Elapsed.TotalSecondss\t Memory:last_memory - first_memory");
long first_memory = GC.GetTotalMemory(true);
var stopWatch = Stopwatch.StartNew();
Console.WriteLine("HasProperty");
dynamic testdo = new A = 1, B = (string)null, C = "A" ;
for (int i = 0; i < LOOP_LENGTH; i++)
if (!TestDynamic.HasProperty(testdo, "A"))
Console.WriteLine("throw find");
break;
if (TestDynamic.HasProperty(testdo, "ABC"))
Console.WriteLine("throw not find");
break;
stopWatch.Stop();
var last_memory = GC.GetTotalMemory(true);
Console.WriteLine($" Time:stopWatch.Elapsed.TotalSecondss\t Memory:last_memory - first_memory");
long first_memory = GC.GetTotalMemory(true);
var stopWatch = Stopwatch.StartNew();
Console.WriteLine("IsPropertyExist");
dynamic testdo = new A = 1, B = (string)null, C = "A" ;
for (int i = 0; i < LOOP_LENGTH; i++)
if (!TestDynamic.IsPropertyExist(testdo, "A"))
Console.WriteLine("throw find");
break;
if (TestDynamic.IsPropertyExist(testdo, "ABC"))
Console.WriteLine("throw not find");
break;
stopWatch.Stop();
var last_memory = GC.GetTotalMemory(true);
Console.WriteLine($" Time:stopWatch.Elapsed.TotalSecondss\t Memory:last_memory - first_memory");
long first_memory = GC.GetTotalMemory(true);
var stopWatch = Stopwatch.StartNew();
Console.WriteLine("IsPropertyExistBinderException");
dynamic testdo = new A = 1, B = (string)null, C = "A" ;
for (int i = 0; i < LOOP_LENGTH; i++)
if (!TestDynamic.IsPropertyExistBinderException(testdo, "A"))
Console.WriteLine("throw find");
break;
if (TestDynamic.IsPropertyExistBinderException(testdo, "ABC"))
Console.WriteLine("throw not find");
break;
stopWatch.Stop();
var last_memory = GC.GetTotalMemory(true);
Console.WriteLine($" Time:stopWatch.Elapsed.TotalSecondss\t Memory:last_memory - first_memory");
long first_memory = GC.GetTotalMemory(true);
var stopWatch = Stopwatch.StartNew();
Console.WriteLine("PropertyExists");
dynamic testdo = new A = 1, B = (string)null, C = "A" ;
for (int i = 0; i < LOOP_LENGTH; i++)
if (!TestDynamic.PropertyExists(testdo, "A"))
Console.WriteLine("throw find");
break;
if (TestDynamic.PropertyExists(testdo, "ABC"))
Console.WriteLine("throw not find");
break;
stopWatch.Stop();
var last_memory = GC.GetTotalMemory(true);
Console.WriteLine($" Time:stopWatch.Elapsed.TotalSecondss\t Memory:last_memory - first_memory");
long first_memory = GC.GetTotalMemory(true);
var stopWatch = Stopwatch.StartNew();
Console.WriteLine("PropertyExistsJToken");
dynamic testdo = new A = 1, B = (string)null, C = "A" ;
for (int i = 0; i < LOOP_LENGTH; i++)
if (!TestDynamic.PropertyExistsJToken(testdo, "A"))
Console.WriteLine("throw find");
break;
if (TestDynamic.PropertyExistsJToken(testdo, "ABC"))
Console.WriteLine("throw not find");
break;
stopWatch.Stop();
var last_memory = GC.GetTotalMemory(true);
Console.WriteLine($" Time:stopWatch.Elapsed.TotalSecondss\t Memory:last_memory - first_memory");
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;
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;
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;
// public static bool HasPropertyExist(dynamic settings, string name)
//
// if (settings is System.Dynamic.ExpandoObject)
// return ((IDictionary<string, object>)settings).ContainsKey(name);
// if (settings is DynamicJsonObject)
// try
//
// return settings[name] != null;
//
// catch (KeyNotFoundException)
//
// return false;
//
// return settings.GetType().GetProperty(name) != null;
//
public static bool IsPropertyExistBinderException(dynamic dynamicObj, string property)
try
var value = dynamicObj[property].Value;
return true;
catch (RuntimeBinderException)
return false;
public static bool HasPropertyFoundException(dynamic obj, string name)
try
var value = obj[name];
return true;
catch (KeyNotFoundException)
return false;
public static bool doesPropertyExist(dynamic obj, string property)
return ((Type)obj.GetType()).GetProperties().Where(p => p.Name.Equals(property)).Any();
public static bool PropertyExistsJToken(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;
// public static bool PropertyExistsJsonObject(dynamic settings, string name)
//
// if (settings is ExpandoObject)
// return ((IDictionary<string, object>)settings).ContainsKey(name);
// else if (settings is DynamicJsonObject)
// return ((DynamicJsonObject)settings).GetDynamicMemberNames().Contains(name);
// return settings.GetType().GetProperty(name) != null;
//
确实存在属性
时间:59.5907507s 内存:403680
有属性
时间:30.8231781s 内存:14968
IsPropertyExist
时间:39.6179575s 内存:97000
IsPropertyExistBinderException 抛出查找
属性存在
时间:56.009761s 内存:13464
PropertyExistsJToken
时间:61.6146953s 内存:15952
【讨论】:
【参考方案14】:为了节省其他人一些时间,这个答案涵盖了很多使用 Newtonstoft Json 动态反序列化谷歌搜索这个问题的人:
dynamic dynamicObject = JsonConvert.DeserializeObject<dynamic>(json);
if (IsContainsKey(dynamicObject, "searchText"))
searchText = dynamicObject.searchText;
bool IsContainsKey(dynamic newtonsoftDynamic, string propertyName)
return (newtonsoftDynamic as JObject).ContainsKey(propertyName);
或者只是在代码中:
JObject obj = dynamicObject as JObject;
string searchText = string.Empty;
if (obj.ContainsKey("searchText"))
searchText = obj.Value<string>("searchText");
没有例外,通过 Newtonsoft 进行正确处理,但您仍然可以将 dynamicObject.xxx 用于您知道将始终存在的属性。
【讨论】:
以上是关于如何检查 C# 中的动态匿名类型上是不是存在属性?的主要内容,如果未能解决你的问题,请参考以下文章