避免单个或默认空引用异常

本文关键字:引用 异常 默认 单个 | 更新日期: 2023-09-27 18:31:52

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

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

避免单个或默认空引用异常

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

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

那将起到作用。


更新:

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

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

为什么不先检查标签:

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

在模型视图控件paradim中,模型应该进行尽可能多的处理,并包含处理其内部结构的逻辑。

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

C# 的重心是在 instance null 时像instance.MethodName()一样在调用中抛出NullReferenceException
对于扩展方法(如SingleOrDefault),在技术上可以编写在instance为空的情况下不会抛出NullReferenceException的方法。例如:

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!");
}

希望有帮助。

我有以下非常通用的扩展方法:

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 => x.Value) 并返回该值。 如果为 null,则返回类型的默认值(或者,也可以根据需要指定另一个所需的默认值)。

我喜欢这种语法,因为它很清楚你想要发生什么,最后用螺栓固定了空处理。

编辑:我刚刚看到这个问题已经有几年了,所以对于最终来到这里的人来说,这是一个对这个问题的新看法。

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

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

您的示例:

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