避免SingleOrDefault空引用异常

时间:2013-09-17 18:20:45

标签: c# linq

我正在添加参数以将信息插入数据库并遇到潜在的空引用异常。通过使用SingleOrDefault LINQ表达式,我认为如果实例没有Tag称为“名称”,则Tag将默认为空值。只要实例具有某种Tag,就是如此。如果实例根本没有标记,则会发生空引用异常。这种情况很少发生,但我仍然需要一种更好的方法来处理它。有没有比捕获异常更好的解决方法?

cmd.Parameters.AddWithValue("@Name", runningInstance.Tag.SingleOrDefault(t => t.Key == "Name").Value);

6 个答案:

答案 0 :(得分:9)

唯一好办法是稍微重建一下你的查询:

instance.Tag.Where(t => t.Key == "Name").Select(T => T.Value).SingleOrDefault();

这样就可以了。


更新

我怀疑您的Tag属性属于IDictionary<,>类型。在这种情况下,检索值的最佳选择是:

TValue value;

if (instance.Tag.TryGetValue("Name", out value))
{
    // We have the value in the value. :)
}
else
{
    // We don't.
}

答案 1 :(得分:1)

NullReferenceException为空时,C#的beaviour会在instance.MethodName()之间通话instance。 对于扩展方法(如SingleOrDefault),技术上可以编写方法,在NullReferenceException为空的情况下不会抛出instance。例如:

public static class MyExtensions
{
    public static string SmartToString(this object instance)
    {
        if(instance == null)return "";
        return instance.ToString()
    }
}

虽然它是非常不常见的方法,因为它通常让人们想到这样的代码:

var instance = null;
// .. several lines later
instance.SmartToString();// why exception is not thrown?? how does this code work at all? ... oh, I see ... that's lame ..

回到你的问题。 SingleOrDefault的实现应该是这样的:如果instance为null,则抛出异常。这就是为什么你必须通过以下代码确保Tag不为空的原因:

if(runningInstance.Tag != null)
{
    cmd.Parameters.AddWithValue("@Name", runningInstance.Tag.SingleOrDefault(t => t.Key == "Name").Value);
}
else
{
    Console.WriteLine("Tag is null!");
}

希望有所帮助。

答案 2 :(得分:0)

为什么不先检查标签:

cmd.Parameters.AddWithValue("@Name",
runningInstance.Tag==null ? null : runningInstance.Tag.SingleOrDefault(t => t.Key == "Name").Value);

答案 3 :(得分:0)

我有以下非常一般的扩展方法:

public static TResult ValueOrDefault<T, TResult>(this T obj, System.Func<T, TResult> getter)
{
    return obj != null ? getter(obj) : default(TResult);
}

public static TResult ValueOrDefault<T, TResult>(this T obj, System.Func<T, TResult> getter, TResult Default)
{
    return obj != null ? getter(obj) : Default;
}

然后你这样称呼它:

instance.Tag.SingleOrDefault(t => t.Key == "Name").ValueOrDefault(x => x.Value);

在英语中,这是说:从枚举中获取单个值。如果该值为非null,则在其上调用指定的选择器函数(x =&gt; x.Value)并返回该值。如果为null,则返回该类型的默认值(如果您愿意,还可以指定其他所需的默认值)。

我喜欢这种语法,因为它很清楚你想要发生什么,最后用最终的空值处理。

答案 4 :(得分:0)

在模型视图控制范例中,模型应该尽可能多地处理并包含处理其内部结构的逻辑。

我建议在runningInstance中添加一个方法,例如GetTag将检查对象是否有Tags,如果是,则返回具有给定键的Tag。此方法将执行所需的所有错误检查,并且在您需要从实例获取标记的任何其他情况下都可以恢复。

答案 5 :(得分:0)

编辑:我刚刚看到这个问题已经有几年了,所以请考虑一下这个问题对于那些最终到此的人来说是一个新的问题。

如果要检查的对象为null,则可以使用null条件运算符(?。)返回null,如果对象不为null,则返回属性值。可从C#6.0获得。

参考:https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-conditional-operators

你的例子:

cmd.Parameters.AddWithValue("@Name", runningInstance.Tag.SingleOrDefault(t => t.Key == "Name")?.Value);