SingleOrDefault()
方法很棒,因为如果你调用它的集合是空的,它不会抛出异常。但是,有时我想要的是获取某种类型的新对象(如果不存在)。例如,如果我能做到以下几点就会很棒:
var client = db.Clients
.Where(c => c.Name == "Some Client")
.SingleOrNew<Client>();
这样我就不必检查它是否为null
,如果它是创建一个新的,我总是知道我的client
对象将是我可以立即使用的东西。
有什么想法吗?
答案 0 :(得分:21)
真的,您只想在这里使用null coalescing运算符。例如:
var client = db.Clients
.Where(c => c.Name == "Some Client")
.SingleOrDefault() ?? new Client();
这将返回SingleOrDefault返回的任何内容,但如果SingleOrDefault返回null,则表达式将返回新的Client()。
编辑:正如John Skeet指出的那样,这个解决方案没有区分没有匹配和找到null元素的情况,但显然这不一定是问题在许多情况下。另一种方法是创建一个扩展方法,如下所示。
public static T SingleOrNew<T>(this IEnumerable<T> query) where T : new()
{
try
{
return query.Single();
}
catch (InvalidOperationException)
{
return new T();
}
}
我想说这可能是一般案例中最优雅的解决方案。
答案 1 :(得分:9)
如果要完成的任务是覆盖默认值(并返回一个新对象),则可以在调用DefaultIfEmpty()之前使用SingleOrDefault()方法执行此操作。类似的东西:
var client = db.Clients
.Where(c => c.Name == name)
.DefaultIfEmpty(new Client { Name = name })
.SingleOrDefault();
答案 2 :(得分:4)
会这样吗? 编辑原来那个??不适用于泛型类型。
public static class IEnumerableExtensions
{
public static T SingleOrNew<T>( this IEnumerable<T> query ) where T : new()
{
var value = query.SingleOrDefault();
if (value == null)
{
value = new T();
}
return value;
}
}
答案 3 :(得分:2)
听起来可以做到,是的。不能说我记得曾经处于我自己使用它的情况,但它很容易实现。像这样:
public static T SingleOrNew<T>(this IEnumerable<T> source) where T : new()
{
if (source == null)
{
throw new ArgumentNullException("source");
}
using (IEnumerator<T> iterator = source.GetEnumerator())
{
if (!iterator.MoveNext())
{
return new T();
}
T first = iterator.Current;
if (iterator.MoveNext())
{
throw new InvalidOperationException();
}
return first;
}
}
我会将其添加到要包含在MoreLinq ...
中的运算符列表中另一种更通用的方法是提供一个只在必要时才进行评估的代表(诚然,我需要一个更好的名字):
public static T SingleOrSpecifiedDefault<T>(this IEnumerable<T> source,
Func<T> defaultSelector)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
if (defaultSelector == null)
{
throw new ArgumentNullException("defaultSelector");
}
using (IEnumerator<T> iterator = source.GetEnumerator())
{
if (!iterator.MoveNext())
{
return defaultSelector();
}
T first = iterator.Current;
if (iterator.MoveNext())
{
throw new InvalidOperationException();
}
return first;
}
}
答案 4 :(得分:1)
为什么不通过Extension方法添加呢?听起来很方便。
答案 5 :(得分:0)
var theClient =
Repository<Client>
.Entities()
.Where(t => t.ShouldBeHere())
.SingleOrDefault()
?? new Client { Name = "Howdy!" }
;