【问题标题】:Is there a way to perform a chained null check in a dynamic/expando?有没有办法在动态/扩展中执行链式空检查?
【发布时间】:2017-10-17 12:55:11
【问题描述】:

C# 有有用的Null Conditional Operatorthis answer 也有很好的解释。

我想知道当我的对象是动态/扩展对象时是否可以进行类似的检查。让我给你看一些代码:

鉴于这个类层次结构

public class ClsLevel1
{
    public ClsLevel2 ClsLevel2 { get; set; }
    public ClsLevel1()
    {
        this.ClsLevel2 = new ClsLevel2(); // You can comment this line to test
    }        
}

public class ClsLevel2
{
    public ClsLevel3 ClsLevel3 { get; set; }
    public ClsLevel2()
    {
        this.ClsLevel3 = new ClsLevel3();
    }       
}

public class ClsLevel3
{
    // No child
    public ClsLevel3()
    {
    }
}

如果我执行这种链式空值检查,它会起作用

ClsLevel1 levelRoot = new ClsLevel1();
if (levelRoot?.ClsLevel2?.ClsLevel3 != null)
{
     // will enter here if you DO NOT comment the content of the ClsLevel1 constructor
}
else
{
     // will enter here if you COMMENT the content of the ClsLevel1 
}

现在,我将尝试通过动态 (ExpandoObjects) 重现此行为

dynamic dinRoot = new ExpandoObject();
dynamic DinLevel1 = new ExpandoObject();
dynamic DinLevel2 = new ExpandoObject();
dynamic DinLevel3 = new ExpandoObject();

dinRoot.DinLevel1 = DinLevel1;
dinRoot.DinLevel1.DinLevel2 = DinLevel2;
//dinRoot.DinLevel1.DinLevel2.DinLevel3 = DinLevel3; // You can comment this line to test

if (dinRoot?.DinLevel1?.DinLevel2?.DinLevel3 != null)
{
     // Obviously it will raise an exception because the DinLevel3 does not exists, it is commented right now.
}

有没有办法用动力学模拟这种行为?我的意思是,检查一长串成员中的 null 吗?

【问题讨论】:

  • 所以您想要does this property exist 支票而不是null 支票?
  • 据我所知 - 没有办法做到这一点。
  • 如果没有办法,那我们就必须建造它。
  • @mjwills 在我的情况下 does this property existsnull check 是一回事

标签: c# .net dynamic expandoobject


【解决方案1】:

如果您想以更自然的方式支持这一点,您可以从 DynamicObject 继承并提供自定义实现:

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

测试:

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

输出将是“它有效!”。由于 Boo 不存在,我们得到一个空引用,因此空条件运算符可以工作。

我们在这里所做的是在每次找不到属性时返回对 TryGetMember 的输出参数的 null 引用,并且我们总是返回 true。

【讨论】:

  • 谢谢@taquion,我做了一些测试,比如:1)使最后一个expando为null或不为null,2)使最后一个对象为null或不为null,3)使“中间- expando" null or not null,到目前为止,一切正常
  • 很高兴知道! \m/ \m/
  • 有没有办法让 MyExpando 像默认动态一样,我的意思是:动态 d = new ExpandoObject(); d.SomeProp = "foo"; //works CustomDynamic c = new CustomDynamic(); c.SomeProp = "酒吧"; //无效
【解决方案2】:

编辑:已修复,因为 ExpandoObjects 和扩展方法不能很好地协同工作。稍微不太好,但希望仍然可以使用。

辅助方法:

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

用法:

if (DynamicExtensions.TryGetProperty(dinRoot, "DinLevel1.DinLevel2.DinLevel3") != null)

【讨论】:

  • 你测试过这个吗?我认为链接不会起作用。
  • 在不支持扩展方法的环境中;不知何故,虽然它会工作。现在更新我的答案。
  • 扩展方法和动态不能很好地混合。此外,“Propertyname”字符串也很碍眼。
猜你喜欢
  • 1970-01-01
  • 2011-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-28
  • 1970-01-01
  • 2011-07-31
  • 1970-01-01
相关资源
最近更新 更多