我想在我的代码中加入一些错误处理。我无法弄清楚如何做以下示例:
public class DataPoints
{
public PointF[] RawData {get; set;} //raw measurement pairs
public float xMax; //max value on X axis
public float yMax; //max value on Y axis
public float GetMaxX()
{
if(RawData == null)
{
throw new NullReferenceException();
return null; //THIS does not compile! I want to exit the method here
}
//DO other stuff to find max X
return MAX_X; //as float
}
}
所以我的想法是,我需要检查是否已设置RawData
,然后在GetMaxX()
方法中执行其余操作。这是一个很好的做法吗?在这种情况下你会做什么?
答案 0 :(得分:5)
此代码存在两个问题,
首先你要抛出异常,然后返回 - 返回语句永远不会被命中,因为异常会停止执行方法的其余部分,使得return语句变得多余。
其次,当返回类型为float时,不能返回null;你必须改变返回类型是浮动的吗? (见:nullable types)
所以要么,如果这是一个真正的错误案例,因为没有什么可以做的只是例外:
public float GetMaxX()
{
if(RawData == null)
throw new NullReferenceException();
//DO other stuff to find max X
return MAX_X; //as float
}
或者,返回null并删除异常:
public float? GetMaxX()
{
if(RawData == null)
return null;
//DO other stuff to find max X
return MAX_X; //as float
}
就个人而言,如果RawData
为null是一个错误条件/异常情况应该永远不会发生,那么我会说抛出异常,并在调用代码中抛出异常处理。
另一种方法是强制RawData
通过构造函数初始化,使RawData
私有(或至少是setter)并在那里抛出异常。保留类中的任何其他逻辑清除抛出/空检查的任何异常,因为它可以假定先前已经设置了RawData
。
导致以下内容:
public class DataPoints
{
private readonly PointF[] rawData; //raw measurement pairs
public float xMax; //max value on X axis
public float yMax; //max value on Y axis
public DataPoints(PointF[] rawData)
{
if (rawData == null)
throw new ArgumentNullException("rawData");
this.rawData = rawData;
}
public float GetMaxX()
{
//DO other stuff to find max X
return MAX_X; //as float
}
}
答案 1 :(得分:2)
如果您要抛出异常,则无论如何都不会执行return语句,因此您正在尝试的正确版本将是
public float GetMaxX()
{
if(RawData == null)
{
throw new NullReferenceException();
}
//DO other stuff to find max X
return MAX_X; //as float
}
return语句不能编译,因为float是一个值类型,除非你使用可空类型float,否则它永远不会为null?
从您给出的代码示例中我个人抛出异常,因为您当前通过公共setter公开RawData对象,因此您无法保证在调用GetMaxX时它不会为null。然后异常可以在堆栈中向上传播并在任何级别捕获,而通过使返回类型为空,您将不得不向调用代码添加额外的检查,以查看您的方法是否返回null并正确处理。
答案 2 :(得分:1)
我不清楚在发生错误时你想做什么。您要抛出异常还是返回null?
一般来说,抛出异常是因为调用者应该知道更好并且您不想尝试恢复 - 让调用者清理混乱。
返回null是指调用者可能有充分的理由不初始化RawData,这在您的情况下是有意义的。为此你需要
public float? GetMaxX()
如果你真的想在没有初始化时爆炸,请将RawData作为参数放在你的构造函数中。
答案 3 :(得分:1)
您可以删除throw异常语句下面的return语句。每当抛出一个异常时,该方法中不会执行任何其他语句(最后块是一个例外,但在此上下文中是无效的。)
除了关于函数的这个问题,我有一个关于RawData属性可以公开访问的论点。打开这样的集合通常不是一个好主意。正如@ sq33G建议的那样,您可以通过将RawData作为构造函数参数传递来保证拥有有效对象。当传递无效数组时,你可以在构造函数的早期失败(null,可能大小为零?)。
private PointF[] _rawData;
public DataPoints(PointF[] rawData)
{
if(rawData == null || rawData.Length == 0)
throw new ArgumentException("RawData should not be null and should contain at least one element");
this._rawData = rawData;
}
如果有必要从类外部访问RawSata,我建议你这样做,既不能改变数组本身(因此没有setter)也不能改变它的内容。使用IEnumerable是一种正确的方法。
public IEnumerable<PointF> RawData
{
get { return _rawData; }
}
答案 4 :(得分:1)
并不总是需要一个方法来返回一个值;特别是,它也被允许退出 通过抛出异常(在这种情况下不返回任何值)。您可以检查规则 here
在您的示例中,您可以
(a)引发NullReferenceException - 这将打破流并返回
(b)如果RawData为null,则返回默认值 - 这将中断流并返回默认值。
float f()
{
if (RawData == null)
{
throw new NullReferenceException();
return default(float);
}
return doOtherOperation(RawData);
}
float doOtherOperation(PointF[] RawData)
{
//do what you wanted to do
return default(float);
}