在投射时避免NullReferenceException的首选做法?

时间:2012-08-16 09:14:50

标签: c# casting nullreferenceexception

我们希望避免使用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#编译器是否足够聪明以优化此性能问题?

我在这里缺少一些其他技术吗?或者上述方法之一是优选的吗?

7 个答案:

答案 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)

如果您想以推测方式进行投射,则建议您使用第一个选项(asnull检查)。但是,您还应该考虑重构代码,以便不再需要强制转换。

答案 5 :(得分:0)

在某些情况下,模式NullObject可以处理它。您可以封装转换机制并返回NullObject。但同样,只有在适合您的情况时才使用它

Null Object pattern wiki page

答案 6 :(得分:0)

您可以使用代理模式以这种方式模拟NullObject

class ClassImplmentsISomeInterfaceProxy:ClassImplmentsISomeInterface
{
      ClassImplmentsISomeInterface target;
      ClassImplmentsISomeInterfaceProxy(ISomeInterface actual)
      {
          target=actual as ClassImplmentsISomeInterface;
      }
      //method implementations, with check for null
}

但确保你真的需要这样的设计:amny类型检查通常意味着有重构的东西。