Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/266.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何检查深lambda表达式中的空值?_C#_Linq_Lambda - Fatal编程技术网

C# 如何检查深lambda表达式中的空值?

C# 如何检查深lambda表达式中的空值?,c#,linq,lambda,C#,Linq,Lambda,如何检查深lamda表达式中的空值 例如,我有一个嵌套了几层的类结构,我想执行以下lambda: x => x.Two.Three.Four.Foo 如果两个、三个或四个为null,我希望它返回null,而不是抛出System.NullReferenceException public class Tests { // This test will succeed [Fact] public void ReturnsValueWhenClass2NotNull()

如何检查深lamda表达式中的空值

例如,我有一个嵌套了几层的类结构,我想执行以下lambda:

x => x.Two.Three.Four.Foo
如果两个、三个或四个为null,我希望它返回null,而不是抛出System.NullReferenceException

public class Tests
{
    // This test will succeed
    [Fact]
    public void ReturnsValueWhenClass2NotNull()
    {
        var one = new One();
        one.Two = new Two();
        one.Two.Three = new Three();
        one.Two.Three.Four = new Four();
        one.Two.Three.Four.Foo = "blah";

        var result = GetValue(one, x => x.Two.Three.Four.Foo);

        Assert.Equal("blah", result);
    }

    // This test will fail
    [Fact]
    public void ReturnsNullWhenClass2IsNull()
    {
        var one = new One();

        var result = GetValue(one, x => x.Two.Three.Four.Foo);

        Assert.Equal(null, result);
    }

    private TResult GetValue<TModel, TResult>(TModel model, Expression<Func<TModel, TResult>> expression)
    {
        var func = expression.Compile();
        var value = func(model);
        return value;
    }

    public class One
    {
        public Two Two { get; set; }
    }

    public class Two
    {
        public Three Three { get; set; }
    }

    public class Three
    {
        public Four Four { get; set; }
    }

    public class Four
    {
        public string Foo { get; set; }
        public string Bar { get; set; }
    }
}

这对于我的域来说基本上是可以的,但有时我真的希望属性返回null。我检查了Josh E的答案,认为它很有用,因为它在某些情况下非常接近我需要的答案。

您可以使用一个通用的助手扩展方法来实现这一点,例如:

public static class Get {
    public static T IfNotNull<T, U>(this U item, Func<U, T> lambda) where U: class {
        if (item == null) {
            return default(T);
        }
        return lambda(item);
    }
}

var one = new One();
string fooIfNotNull = one.IfNotNull(x => x.Two).IfNotNull(x => x.Three).IfNotNull(x => x.Four).IfNotNull(x => x.Foo);
private Two _two;
public Two Two
{
     get 
     {
       if (null == _two)
         return new Two();
       else
         return _two;
      }
}
公共静态类Get{
公共静态T IfNotNull(此U项,Func lambda),其中U:class{
如果(项==null){
返回默认值(T);
}
返回lambda(项目);
}
}
var one=新的一个();
字符串fooinfotnull=one.IfNotNull(x=>x.Two).IfNotNull(x=>x.Three.IfNotNull(x=>x.Four.IfNotNull)(x=>x.Foo);

在使用属性之前,请始终初始化属性。向类1、2、3和4添加构造函数。在构造函数中,初始化属性,使其不为空。

您不能以简洁的方式完成此操作。可以将lambda设置为多行,也可以使用嵌套的三元运算符:

var result = GetValue(one, x => x.Two == null ? null :
                                x.Two.Three == null ? null :
                                x.Two.Three.Four == null ? null :
                                x.Two.Three.Four.Foo;

丑陋,我知道。

您可以修改您的getter,使其内容如下:

public static class Get {
    public static T IfNotNull<T, U>(this U item, Func<U, T> lambda) where U: class {
        if (item == null) {
            return default(T);
        }
        return lambda(item);
    }
}

var one = new One();
string fooIfNotNull = one.IfNotNull(x => x.Two).IfNotNull(x => x.Three).IfNotNull(x => x.Four).IfNotNull(x => x.Foo);
private Two _two;
public Two Two
{
     get 
     {
       if (null == _two)
         return new Two();
       else
         return _two;
      }
}
我对c#不太熟悉,但也许有某种方法可以从ruby中实现“AND”模式,从而在不影响实现的情况下解决这个问题

这个概念在Haskell中也被称为Maybe Monad


这篇文章的标题似乎很有希望。

我发现coalesce操作符有时对此很有用。不过,这只有在存在可插入的对象的默认/空等效版本时才有帮助

例如,有时当我打开XML时

IEnumeratable<XElement> sample;
sample.Where(S => (S.Attribute["name"] ?? new XAttribute("name","")).Value.StartsWith("Hello"))...
i可计量样本;
sample.Where(S=>(S.Attribute[“name”]?new XAttribute(“name”,”).Value.StartsWith(“Hello”)。。。

根据默认对象的检索方式,这可能会很冗长,上面的示例并没有多大用处,但您已经明白了这一点。对于读取XML属性的特殊情况,我有一个返回属性值或空字符串的扩展方法。

简单地执行此操作需要一个尚未实现的运算符。我们考虑在C#4.0中添加一个操作符“?”,它将具有您想要的语义,但不幸的是,它不适合我们的预算。我们将把它当作一个假设的未来版本的语言。

现在可以使用CODULTEX项目。

语法是:

string result = One.Maybe(o => o.Two.Three.Four.Foo);

string cityName = Employee.Maybe(e => e.Person.Address.CityName);

我将一个函数转换为.IFNotNull方法,该函数使用了大量if语句来避免空值,该方法用于我从深度为4和5级的XSD转换的类

以下是几行转换后的代码:

ProdYear.Previous_CUMULATIVE_CARBON_VALUE=year.IfNotNull(x=>x.Previous_CUMULATIVE).IfNotNull(y=>y.CARBON_CO2).IfNotNull(z=>z.VALUE).ToDouble();
ProdYear.Previor\u CUMULATIVE\u CARBON\u CO2\u UOM=year.IfNotNull(x=>x.Previor\u CUMULATIVE)。IfNotNull(y=>y.CARBON\u CO2)。IfNotNull(z=>z.UOM);
以下是一些有趣的统计数据:

1) 这个新方法比使用If语句运行变量的时间长3.7409倍。
2) 我将功能行计数从157减少到59。

3) DevXPress的“维护复杂性”得分为。当我转换到Lambda语句时,它从984增加到2076,这在理论上更难维护

我已经编写了一个扩展方法,使您能够执行以下操作:

blah.GetValueOrDefault(x => x.Two.Three.Four.Foo);
在返回表达式值之前,它使用表达式树在每个节点上构建一个嵌套的空值条件检查;创建的表达式树被编译成一个
Func
并被缓存,因此相同调用的后续使用应该以几乎本机的速度运行

如果愿意,还可以传入要返回的默认值:

blah.GetValueOrDefault(x => x.Two.Three.Four.Foo, Foo.Empty);

我写了一篇关于它的博客。

在这种情况下,我想返回Foo或Bar类型的默认值。我真正想要避免的是,如果表达式树中更高的部分为空,则会出现异常。我编辑了答案,并添加了一个代码示例,该示例编译得很好,应该可以做到这一点。这容易吗?那么优雅+1,并且没有因反射而影响运行时性能。有没有人根据Gabe的解决方案或“正常”方法对此进行基准测试?我通常会这样做,但在这个域中,属性有时会设置为null。这是一种有效的行为。有趣的是,这篇文章几乎与我通过思考得出的解决方案完全相同,请参阅我的帖子……哇,完全错过了它,我想我是在寻找“可能”这个词可以。修改实现以保存客户端代码中的一些行会触发各种警报。我倾向于不同意这是一个问题:我将此称为防御编码。上面的代码确保了一个属性的值在没有与该属性/对象的任何使用者共享该知识的情况下永远不会为null。如果我在_Two为null时继续调用Two,我会不断得到Two的新实例。。。ewgood point。在这种情况下,您可以修改它,在返回它之前将_two设置为一个新的two()实例,例如if(null==_two)_two=new two();返回2;这太好了!Delphi prism对它的“:”操作符做了同样的操作:我支持它。这将使许多代码变得更加干净!此功能现在已在c#6中!我尝试在这个问题案例中使用“?”,但这是不允许的。。。它导致错误
错误CS8072表达式树lambda可能不包含null传播运算符。
这里的一些讨论:这是一个更简洁的方法。可能(x=>x.Two.Three.Foo);请参见使用表达式树是否会影响性能?执行不同操作是否会改变性能特征?对您或用户会注意到这一点吗?我不知道你的用法,请描述一下。