Как вернуть NULL для «метода с плавающей точкой» - Обработка ошибок - PullRequest
1 голос
/ 01 ноября 2011

Я хочу добавить обработку ошибок в мой код.Я не могу понять, как это сделать для следующего примера:

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().Это хорошая практика на всех?Что бы вы сделали в этом случае?

Ответы [ 5 ]

5 голосов
/ 01 ноября 2011

У этого кода есть две проблемы:

Сначала вы генерируете исключение, а затем возврат - оператор return никогда не будет выполнен, поскольку исключение остановит выполнение остальной части метода., делая обратное утверждение излишним.

Во-вторых, вы не можете вернуть ноль, если тип возвращаемого значения - float;Вы должны изменить тип возвращаемого значения, чтобы быть с плавающей точкой?(см .: обнуляемые типы )

Так что либо, если это настоящая ошибка, так как вы ничего не можете сделать, просто исключение:

   public float GetMaxX()
   {
       if(RawData == null)
          throw new NullReferenceException();

     //DO other stuff to find max X
     return MAX_X; //as float
   }

Или, в качестве альтернативы, верните ноль и отбросьте исключение:

   public float? GetMaxX()
   {
       if(RawData == null)
          return null; 

     //DO other stuff to find max X
     return MAX_X; //as float
   }

Лично, если RawData значение ноль - это условие ошибки / исключительное обстоятельство, которое никогда не должно произойти, тогда я бы сказал, бросить исключение и обработатьисключение, если выброшено в вызывающем коде.

Альтернативный подход заключается в том, чтобы принудительно инициализировать RawData через конструктор, сделать RawData приватным (или, по крайней мере, установщиком) и вызвать там исключение.Оставляя любую другую логику внутри класса чистой от любых исключений, бросающих / проверяющих на ноль, поскольку можно предположить, что 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
    }
}
2 голосов
/ 01 ноября 2011

Если вы генерируете исключение, оператор return все равно не будет выполнен, поэтому правильная версия того, что вы пытаетесь сделать, будет

  public float GetMaxX()
  {
      if(RawData == null)
      {
         throw new NullReferenceException();
      }

      //DO other stuff to find max X
      return MAX_X; //as float
   }

Оператор return не скомпилируется, потому что float являетсятип значения, который никогда не может быть нулевым, если вы не используете тип с плавающей запятой?

Лично из приведенного вами примера кода я бы выдал исключение, поскольку вы в настоящее время открываете объект RawData с помощью общедоступного установщика, так что у вас нетгарантируйте, что он не будет нулевым, когда вызывается GetMaxX.Затем исключение можно распространить вверх по стеку и перехватить на любом уровне, тогда как, сделав возвращаемый тип обнуляемым, вам придется добавить дополнительные проверки к вызывающему коду, чтобы увидеть, вернул ли ваш метод значение null, и обработать это соответствующим образом.

1 голос
/ 01 ноября 2011

Метод не всегда требуется для возврата значения;в частности, ему также разрешается выход, выдавая исключение (в этом случае значение не возвращается).Вы можете проверить правило здесь

В вашем примере вы можете либо

(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);
    }
1 голос
/ 01 ноября 2011

Вы можете удалить оператор возврата, который находится ниже оператора исключения исключения.Всякий раз, когда генерируется исключение, никакие другие операторы не выполняются в методе (наконец, блоки являются исключением из этого, но не имеют значения в этом контексте).

За исключением этой проблемы с функцией, у меня есть аргумент о RawDataсобственность доступна публично.Как правило, не стоит открывать такую ​​коллекцию.Как подсказывает @ sq33G, вы можете гарантировать наличие действительного объекта, передавая RawData в качестве параметра конструктора.И вы можете потерпеть неудачу в начале конструктора, когда передан неверный массив (ноль, может быть, нулевого размера?).

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 был доступен извне класса, я предлагаю вамсделать это таким образом, чтобы ни сам массив (то есть никакой установщик), ни его содержимое не могли быть изменены.Использование IEnumerable является правильным способом сделать это.

public IEnumerable<PointF> RawData
{
    get { return _rawData; }
}
1 голос
/ 01 ноября 2011

Мне не ясно, что вы хотите сделать в случае ошибки.Вы хотите выбросить исключение или вернуть ноль?

Вообще говоря, исключение - это когда вызывающий должен был знать лучше, а вы не хотите пытаться восстановиться - пусть вызывающий исправит беспорядок.

Возвращаемое значение null предназначено для случаев, когда у вызывающей стороны могла быть веская причина не инициализировать RawData, что имеет смысл в вашем случае.Для этого вам нужно иметь

public float? GetMaxX()

Если вы действительно хотите взорвать, когда ничего не инициализировано, поместите RawData в качестве параметра в ваш конструктор.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...