我一直在向我的团队介绍一些新的C#语言功能 - 安全导航就是其中之一。
是否有任何重要的性能原因可以避免为每个对象/属性调用使用安全导航?
e.g:
myObject?.Field?.FieldValue
VS
myObject.Field.FieldValue
我知道这样做会使每个字段都被空检查 - 但是在紧密循环之外,不要抓住这些错误让它值得吗?或者这是否鼓励懒惰编码?
编辑:
我在这个主题上找到entire article,希望它对其他人有帮助!
答案 0 :(得分:7)
这个捕获的错误不值得吗?
恰恰相反:在任何地方应用安全导航都会隐藏错误,而非捕捉错误。
错误地导航null
引用是实现中的一个错误,可能意味着以下两种情况之一:
null
null
- 检查合法null
对于案例#2,应用安全导航是一个不错的选择,因为它允许您使用更少的代码执行空检查。但是,对于情况#1来说,这是一个糟糕的选择,因为从程序逻辑的角度来看,它允许对象或变量保持不正确的状态。
这就是为什么程序员在应用安全导航时应该自行决定,单独决定每个案例。
答案 1 :(得分:1)
时无法安全导航
1)Null实际上是你正在做的事情的无效逻辑
public string ProcessHash(User user)
{
var hash = user?.Password?.Hash
...
}
它被称为安全导航不容易空检查有一个原因。想象一下,你注定要阅读上面的代码。 ProcessHash是否期望用户参数为空参数?如果是这样,它的Password属性是否也应该变为null?你怎么知道以前的编码器是否使用过“?”。代替 ”。”只是因为他是猫王的粉丝?你必须分析整个代码才能找到答案。
2)Null在代码中具有另一个含义而不是不可用
盲人看到了什么?黑暗?或者根本没有?
什么是空的杂货篮?
// This is a good
Basket<Grocery> basket = new Basket<Grocery>();
var count = basket.Count(); // returns 0
// This smells bad!
Basket<Grocery> basket = null
var count = basket?.Count ?? 0;
3)你在用?和扩展方法作为管道运算符!
不要使用?将属性和方法链接在一起只是因为它减少了你编写的行并使代码变冷。在其他语言中看到的花哨功能代码中,管道后面有许多更深思熟虑的高级抽象。
var resp = this.Bind<IceCreamDTO>()?.Validate()?.ToEntity()?.Insert()?.ToResponse();
上面的代码有两个问题。
想象一下,在验证绑定对象时是否存在错误。你能把它的错误归还给请求者吗?嗯,你可以...但它很糟糕。
// That's not how this works. that's not how any of this works.
try
{
var resp = this.Bind<IceCreamDTO>()?.Validate()?.ToEntity()?.Insert()?.ToResponse();
...
} catch (ValidationException exp)
{
return exp.Errors.ToResponce();
}
在上面的例子中并没有清楚(意识到它是所有方法调用而不是属性调用),如果你在一起导航方法和属性,这也可能会打破封装原则。
// Privacy violation
bool passwordValidation = user?.Password?.Hash?.Validate(hash);
// Property Security
bool passwordValidation = PasswordHash.Validate(user, hash);