LINQ:当对象可能为null时,选择属性的更好方法是什么
本文关键字:属性 选择 更好 是什么 方法 null 对象 LINQ | 更新日期: 2023-09-27 17:57:30
var result = foo.FirstOrDefault(f => f.bar == barVal).someProperty
如果不匹配(默认值为null(-尝试访问null对象上的属性,这将不起作用。我们可以重写如下:
var result = foo.Where(f => f.bar == barVal)
.Select(f => f.someProperty).DefaultIfEmpty(0).First()
虽然它有效,但这似乎不是最优雅的方式有更好的方法吗
当然,人们可以做一些事情,比如:
var result = 0;
var tmp = foo.FirstOrDefault(f => f.bar == barVal);
if(tmp != null) result = tmp.someProperty
但在更复杂的查询中,这种方法看起来比DefaultIfEmpty方法更"混乱">
var tmpSet = dataSet.GroupBy(f => f.ID);
var newSet = tmp.Select(f => new {
ID = f.ID,
SomeProperty = f.Where(g => g.bar == barVal)
.Select(f => f.SomeProperty)
.DefaultIfEmpty(0).First()
});
您可以这样做:
var result = foo.Where(f => f.bar == barVal)
.Select(f => f.someProperty)
.FirstOrDefault();
或者你可以写一个自定义的扩展方法:
public static TResult IfNotNull<TSource, TResult>(this TSource instance, Func<TSource, TResult> getter, TResult defaultValue = default(TResult))
where TSource : class
{
if (instance != null)
return getter(instance);
return defaultValue;
}
...
var result = foo.FirstOrDefault(f => f.bar == barVal)
.IfNotNull(f => f.someProperty);
编辑:使用C#6,您将能够编写以下内容:
var result = foo.FirstOrDefault(f => f.bar == barVal)?.someProperty ?? 0;
有关详细信息,请参阅Roslyn Codeplex网站上的讨论。
不久前我问了一个类似的问题;我发现最好的方法是使用来自FirstOrDefault
的默认值,或者使用DefaultIfEmpty
作为非默认值。只需先在Select
Linq查询中取消引用属性
所以我真的看不出有什么更好的方法来取消对该房产的引用。扩展方法是将这种行为折叠为更具表达性的名称的唯一方法。
目前最有意识的解决方案似乎是一种扩展方法。
var foo = "foo";
var fooNull = (String)null;
var fooLength = foo.Get(_ => _.Length, -1); // 3
var fooNullLength = fooNull.Get(_ => _.Length, -1); // -1
var bar = new[] { "bar" };
var barNull = new[] { (String)null };
var barLength = bar.GetSingle(_ => _.Length, -1); // 3
var barNullLength = barNull.GetSingle(_ => _.Length, -1); // -1
var baz = new[] { null, "bar", null };
var bazLength = baz.Get(_ => _.Length, -1); // { -1, 3, -1 }
我将按如下方式实现,为了简洁起见,省略了错误处理。请注意,我在这里使用了比上面的示例更有意义但更长的方法名称。
// Get the value of a property of an object or a default
// value if the object is null.
public static TProperty GetGetPropertyValueOrDefault<TObject, TProperty>(this TObject obj, Func<TObject, TProperty> propertyValueGetter, TProperty defaultValue = default(TProperty))
where TObject : class
{
return (obj != null) ? propertyValueGetter(obj) : defaultValue;
}
// Get the value of a property for the single object in a
// sequence or a default value if the sequence is empty.
public static TProperty GetSinglePropertyValueOrDefault<TObject, TProperty>(this IEnumerable<TObject> sequence, Func<TObject, TProperty> propertyValueGetter, TProperty defaultValue = default(TProperty))
where TObject : class
{
return sequence.SingleOrDefault().GetGetPropertyValueOrDefault(propertyValueGetter, defaultValue);
}
// Get the value of a property or a default value if the
// object is null for all objects in a sequence.
public static IEnumerable<TProperty> GetGetPropertyValuesOrDefault<TObject, TProperty>(this IEnumerable<TObject> sequence, Func<TObject, TProperty> propertyValueGetter, TProperty defaultValue = default(TProperty))
where TObject : class
{
return sequence.Select(element => element.GetGetPropertyValueOrDefault(propertyValueGetter, defaultValue));
}