我们希望避免使用NullReferenceException
。目前我们有:
ISomeInterface interface = this.GetISomeInterfaceInstance();
(interface as ClassImplmentsISomeInterface).Method();
这很好,但有风险NullReferenceException
。一种解决方案是:
ISomeInterface interface = this.GetISomeInterfaceInstance();
ClassImplmentsISomeInterface instance = interface as ClassImplmentsISomeInterface;
if (instance != null)
instance.Method();
但是这会产生很多额外的代码用于简单的检查(根据resharper,有100个可能的NRE。)第二种解决方法是:
ISomeInterface interface = this.GetISomeInterfaceInstance();
if (interface is ClassImplmentsISomeInterface)
(interface as ClassImplmentsISomeInterface).Method();
但我认为is
实际上在背景中使用了as
,因此进行了两次演员,这是我想避免的。这有关系吗?例如,C#编译器是否足够聪明以优化此性能问题?
我在这里缺少一些其他技术吗?或者上述方法之一是优选的吗?
答案 0 :(得分:4)
我可以想出一个可以缩短代码的好方法:
public static void InvokeIfIsT<T>(object o, Action<T> action)
{
if (o is T)
action((T)o);
}
使用它:
ISomeInterface interface = this.GetISomeInterfaceInstance();
InvokeIfIsT<ClassImplmentsISomeInterface>(interface, i => i.Method());
答案 1 :(得分:2)
你是正确的is
使用as
并且如果结果不是true
则返回布尔null
(反之亦然)
但是我建议你把resharper规则作为提示或指导而不是遵循的规则(我实际上将其关闭),我说这是因为抛出NullReferenceException没有任何问题
考虑你的代码
ISomeInterface interface = this.GetISomeInterfaceInstance();
(interface as ClassImplmentsISomeInterface).Method();
//error thrown above as null reference
现在你继续将其重构为
ISomeInterface interface = this.GetISomeInterfaceInstance();
if (interface is ClassImplmentsISomeInterface)
{
(interface as ClassImplmentsISomeInterface).Method();
}
else
{
//else?? else what? how do you recover?
}
如果异常只是异常
,则异常没有错现在您可能会说&#34;处理其他方案的成本低于例外情况&#34;但只有你可以恢复的情况才会出现,例如,如果你能写出像这样的东西
ISomeInterface interface = this.GetISomeInterfaceInstance();
try
{
(interface as ClassImplmentsISomeInterface).Method();
}
catch (NullReferenceException)
{
interface = this.GetIOtherInterface().Method();
}
然后,当你实际做一些有用的事情时,值得重构为空检查。如果你的方法不能优雅地恢复,那么你的方法需要向某个地方抛出一个例外来表示&#34;嘿,出了点问题&#34;
答案 2 :(得分:1)
如果我认为某些内容可能为空,我个人只会使用!= null
测试。但是如果是因为你将一个Interface对象转换为一个具体的对象,那么我认为你必须退一步重新评估你的设计。如果我必须将Interface对象强制转换为具体对象以便使用它,我认为自己失败了。
使用工厂获取实现接口的对象,但是必须将其强制转换为具体对象才能使用它是禁忌恕我直言。如果接口指定了一个方法,那么您不应该关心哪种对象实现了该接口。如果您关心该方法的作用,那么您应该创建一个不同的接口并让您的具体类实现它。
请记住,类可以实现任意数量的接口。
答案 3 :(得分:0)
我通常会选择
ISomeInterface variable = this.GetISomeInterfaceInstance();
var myInterface = variable as ClassImplmentsISomeInterface;
if(myInterface != null)
myInterface.Method();
答案 4 :(得分:0)
如果您想以推测方式进行投射,则建议您使用第一个选项(as
和null
检查)。但是,您还应该考虑重构代码,以便不再需要强制转换。
答案 5 :(得分:0)
在某些情况下,模式NullObject可以处理它。您可以封装转换机制并返回NullObject。但同样,只有在适合您的情况时才使用它
答案 6 :(得分:0)
您可以使用代理模式以这种方式模拟NullObject
:
class ClassImplmentsISomeInterfaceProxy:ClassImplmentsISomeInterface
{
ClassImplmentsISomeInterface target;
ClassImplmentsISomeInterfaceProxy(ISomeInterface actual)
{
target=actual as ClassImplmentsISomeInterface;
}
//method implementations, with check for null
}
但确保你真的需要这样的设计:amny类型检查通常意味着有重构的东西。