C# 当工厂方法返回null时,我应该抛出什么异常?

C# 当工厂方法返回null时,我应该抛出什么异常?,c#,.net,C#,.net,考虑一个我可以控制也可以不控制的工厂方法,作为Func传递给另一个类: //this.FactoryMethod是传递到此类的外部依赖项 //通过构造函数或属性注入,假定它不是null //但不能保证它将返回非空引用。 功能因子法; 公共IModel GetPopulatedModel(int状态,FileInfo someFile) { //为简洁起见,省略了参数验证。。。 //此操作可能返回null。 var model=this.FactoryMethod() if(mode

考虑一个我可以控制也可以不控制的工厂方法,作为
Func
传递给另一个类:

//this.FactoryMethod是传递到此类的外部依赖项
//通过构造函数或属性注入,假定它不是null
//但不能保证它将返回非空引用。
功能因子法;
公共IModel GetPopulatedModel(int状态,FileInfo someFile)
{       
//为简洁起见,省略了参数验证。。。
//此操作可能返回null。
var model=this.FactoryMethod()
if(model==null)
{
抛出新的SomeException(“工厂方法无法生成值”);
}
//此时可以安全地分配给属性。
模型。优先级=状态;
model.File=someFile;
收益模型;
}
我想抛出一些指示操作失败的东西

ArgumentNullException
会产生误导,因为参数没有任何错误:

当一个空引用(在Visual Studio中为Nothing)时引发的异常 Basic)传递给不接受其为有效 争论

InvalidOperationException
似乎不太恰当:

当方法调用对的无效时引发的异常 对象的当前状态

认为将局部变量作为代码的一部分似乎很奇怪,对象的当前状态< /代码> < /P>


抛出什么样的异常比较好?我很惊讶
系统中没有
操作失败异常
。我应该编写自己的异常,还是有一个好的异常?

如果您觉得可用的异常不充分,您可以随时创建自己的异常

更新
尽管如此,我还是同意@TomTom和@dtb关于可能存在的选项的看法。尤其是
NotImplementedException
,因为工厂确实没有实现

我会创建自己的异常,称为

FactoryNullException

然后,您甚至可以创建所需的默认消息,例如示例中的消息

Factory method failed to produce a value.

无效操作例外

局部变量是根据定义定义对象状态的变量。没什么不好的。必须设置factory方法,否则无法创建对象。InvalidOperation-工厂当时无法创建对象,因为工厂的内部状态不正确。

可能

NullReferenceException

是您想要的。

来自.NET Framework的两个示例:

  • 如果返回null,则抛出

    无效操作异常类

    当方法调用对于对象的当前状态无效时引发的异常

  • 如果返回null,则抛出

    未实现异常类

    当请求的方法或操作未实现时引发的异常

CloneCore本质上是当前对象克隆的工厂方法


我会使用NotImplementedException,因为factory方法不会实现它所请求的内容。

我不确定这是否就是您在这里实现的factory模式。但要回答您的问题,只需做如下自定义例外:

public class FactoryNullException : Exception
{
    public FactoryNullException() : base("Factory was null")
    {

    }
}

为什么不使用InvalidOperationException(),因为如果该方法失败,您就无法控制所使用的方法,这意味着该方法无效。

另一个选项:不要抛出异常。在实际应用程序中,该方法是从try/catch块中调用的,该异常将被捕获并记录。在这种情况下,抛出异常没有任何好处

因此,我没有抛出异常,而是记录消息并返回null。将其转换为示例代码如下所示:

// this.FactoryMethod is an external dependency passed into this class
// through constructor or property injection assume that it is not null
// but there is no guarantee that it will return a non-null reference.
Func<IModel> FactoryMethod;

public IModel GetPopulatedModel(int state, FileInfo someFile)
{       
   // Argument validation omitted for brevity...

   // This operation could return null.
   var model = this.FactoryMethod()
   if (model == null)
   {
      this.Logger.Write("Factory method failed to produce a value.");
      return null;
   }

   // Safe to assign to properties at this point.
   model.Priority = state;
   model.File = someFile;
   return model;
}
//this.FactoryMethod是传递到此类的外部依赖项
//通过构造函数或属性注入,假定它不是null
//但不能保证它将返回非空引用。
功能因子法;
公共IModel GetPopulatedModel(int状态,FileInfo someFile)
{       
//为简洁起见,省略了参数验证。。。
//此操作可能返回null。
var model=this.FactoryMethod()
if(model==null)
{
this.Logger.Write(“工厂方法无法生成值”);
返回null;
}
//此时可以安全地分配给属性。
模型。优先级=状态;
model.File=someFile;
收益模型;
}

如果抛出异常是必需的/有用的,我会选择
NotImplementedException
,但在这种情况下,不抛出异常更有意义。

NotImplementedException肯定不是正确的选择,而且它几乎不应该被生产代码抛出

在这个场景中抛出什么的最重要标准是什么对异常的消费者最有用。如果您期望调用代码对该异常的反应可能与对任意异常的反应不同,那么异常类型非常重要。另一方面,对于这样的异常,调用代码所能做的唯一一件事就是记录它,它的消息非常重要,它的类型也不那么重要。在后一种情况下,带有显式消息的InvalidOperationException可能非常合适

同样值得考虑的是,从工厂方法返回空值是否应该被视为违反其合同。在这种情况下,您希望抛出异常这一事实表明它可能应该抛出异常,在这种情况下,您可能希望稍微更改设计,以便注入接口实例,而不是
Func
。这将允许您在接口方法上定义一个文档化的契约,指定它永远不会返回null,并且
// this.FactoryMethod is an external dependency passed into this class
// through constructor or property injection assume that it is not null
// but there is no guarantee that it will return a non-null reference.
Func<IModel> FactoryMethod;

public IModel GetPopulatedModel(int state, FileInfo someFile)
{       
   // Argument validation omitted for brevity...

   // This operation could return null.
   var model = this.FactoryMethod()
   if (model == null)
   {
      this.Logger.Write("Factory method failed to produce a value.");
      return null;
   }

   // Safe to assign to properties at this point.
   model.Priority = state;
   model.File = someFile;
   return model;
}