Is there a way to perform a chained null check in a dynamic/expando?

那年仲夏 提交于 2019-12-01 10:39:27
taquion

If you want to support this in a more natural way you can inherit from DynamicObject and provide a custom implementation:

class MyExpando : DynamicObject
    {
        private readonly Dictionary<string, object> _dictionary = new Dictionary<string, object>();

        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            var name = binder.Name.ToLower();
            result = _dictionary.ContainsKey(name) ? _dictionary[name] : null;
            return true;
        }

        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            _dictionary[binder.Name.ToLower()] = value;
            return true;
        }
    }

Testing:

 private static void Main(string[] args)
        {
            dynamic foo = new MyExpando();
            if (foo.Boo?.Lol ?? true)
            {
                Console.WriteLine("It works!");
            }
            Console.ReadLine();
        }

The output will be "It works!". Since Boo does not exist we get a null reference so that the Null Conditional Operator can work.

What we do here is to return a null reference to the output parameter of TryGetMember every time a property is not found and we always return true.

EDIT: fixed, as ExpandoObjects and extension methods do not work well together. Slightly less nice, but hopefully still usable.

Helper method(s):

public static class DynamicExtensions
{
    public static Object TryGetProperty(ExpandoObject obj, String name)
    {
        return name.Split('.')
                   .Aggregate((Object)obj, (o, s) => o != null
                                                      ? TryGetPropertyInternal(o, s)
                                                      : null);
    }

    private static Object TryGetPropertyInternal(Object obj, String name)
    {
        var dict = obj as IDictionary<String, Object>;
        return (dict?.ContainsKey(name) ?? false) ? dict[name] : null;
    }
}

Usage:

if (DynamicExtensions.TryGetProperty(dinRoot, "DinLevel1.DinLevel2.DinLevel3") != null)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!