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

我有一个匿名类型对象,它是从一个方法接收到的动态对象 我想检查该对象上存在的属性。

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


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

如何实现 IsSettingExist?

152207 次浏览

如果您可以控制创建/传递设置对象,那么我建议您使用 ExpendoObject 来代替。

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 ....
}
  public static bool DoesPropertyExist(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(DoesPropertyExist(settings, "Filename"));
Console.WriteLine(DoesPropertyExist(settings, "Size"));

产出:

 True
False
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 IsPropertyExist(dynamic dynamicObj, string property)
{
try
{
var value=dynamicObj[property].Value;
return true;
}
catch (RuntimeBinderException)
{


return false;
}


}

使用反射,这是我使用的函数:

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

然后。

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

上面的解决方案都不适用于来自 Jsondynamic,但是我设法用 Try catch(by@user3359453)通过改变抛出的异常类型(KeyNotFoundException而不是 RuntimeBinderException)将其转换成实际可行的..。

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

enter image description here

希望这能为你节省点时间。

合并和修复来自 Serj-TM 和 user3359453的答案,以便它可以同时使用 ExpendoObject 和 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;
}

这适用于匿名类型,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;
}

如果有人需要处理来自 Json 的动态对象,我已经修改了 Seth Reno answer 来处理从 Newton Soft 反序列化的动态对象。Jason JObject.

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;
}

要扩展@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;
}

这也适用于 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;
}
    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.TotalSeconds}s\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.TotalSeconds}s\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.TotalSeconds}s\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.TotalSeconds}s\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.TotalSeconds}s\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.TotalSeconds}s\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;
// }
}

DoesPropertyExist

时间: 59.5907507 s 内存: 403680

HasProperty

时间: 30.8231781 s 内存: 14968

IsPropertyExist

时间: 39.6179575 s 内存: 97000

抛出查找

Property 存在

时间: 56.009761 s 内存: 13464

Property 存在 JToken

时间: 61.6146953 s 内存: 15952

我碰到的动态是 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;
}
}

使用 switch 表达式编辑 智能解决方案

public static bool PropertyExists(dynamic obj, string name)
{
if (obj == null) return false;
return obj switch
{
IDictionary<string, object> dict => dict.ContainsKey(name),
Newtonsoft.Json.Linq.JObject jObject => jObject.ContainsKey(name),
_ => obj.GetType().GetProperty(name) != null
};
}

为了节省其他人的时间,这个答案涵盖了很多使用 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 ,因为你知道这些房产永远都会在那里。