Как я должен обрабатывать неправильный пользовательский ввод в этом случае? - PullRequest
2 голосов
/ 06 октября 2009

Я пишу плагин для программы геометрического моделирования, и у меня есть абстрактный класс, основанный на объекте Curve. Кривая считается действительной, только если она плоская, замкнутая и не пересекает себя.

Затем у меня есть цепочка других методов, которые ссылаются на эту кривую, которые делают такие вещи, как создание из нее поверхности или выдавливание ее в объем. Эти методы выдают исключение, если они вызываются, когда BaseCurve недопустим. Прямо сейчас моя программа просто падает, если пользователь делает недействительной одну из кривых, и я пытаюсь найти лучший способ, чтобы моя программа обработала этот неверный ввод.

Вот как выглядит мой класс:

public abstract class AbsCurveBasedObject
{
    public abstract Curve BaseCurve
    {
        get;
    }

    public bool BaseCurveIsValid
    {
        get
        {
            Curve c = this.BaseCurve;
            ...
            //checks that curve is valid
            ...
            return true/false;
        }
    }

    public Surface GetSurface()
    {
         Curve c = this.BaseCurve();
         ...
         //magic that converts c to a surface
         //exception is thrown if c is invalid
         ...
         return surface;
    }

    public Surface GetVolume()
    {
         Surface s = this.GetSurface();
         ...
         //magic that converts s into a volume
         ...
         return volume;
    }
}

Я не уверен, что GetSurface () должен возвращать NULL , если кривая недействительна или я должен вызвать исключение.

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

Должен ли я вместо этого просто возвращать NULL из GetSurface (), если кривая недействительна, и затем каждый метод, основанный на GetSurface (), также возвращает null, если GetSurface () делает? Кажется, это будет сложнее отлаживать. Я знаю, что в конечном итоге забуду проверить, является ли возвращаемое значение где-либо NULL, и получу какое-то ArgumentNullException, которое отслеживает весь путь до AbsCurveBasedObject.GetSurface ()

Так лучше ли иметь блоки if / else или try / catch по всему месту отслеживания для обработки, когда пользователь как-то делает недействительным свойство базовой кривой?

Ответы [ 3 ]

2 голосов
/ 06 октября 2009

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

Посмотри на это так. Ваш код, вероятно, выглядит так:

Blah MakeMeABlah(Foo foo)
{
  if (!IsValid(foo)) throw new InvalidArgumentException("foo");
  // [make a blah from a foo]
}

Вы можете сделать так, чтобы вызывающий абонент выглядел так:

Foo foo = GetFooFromUser();
try
{
    blah = MakeMeABlah(foo);
}
catch(...)
{
   // Tell user that input foo was invalid
}

Это не так хорошо. Решением вашей проблемы является превращение IsValid в публичный метод:

Foo foo = GetFooFromUser();
if (!IsValid(foo))
   // Tell user that input foo was invalid
else
   blah =  MakeMeABlah(foo);

И, эй, обработки исключений нет, ценой необходимости дважды вызывать IsValid . Если проверка дешевая, кого это волнует? Если проверка обходится дорого, вы можете захотеть провести дальнейшую реорганизацию, чтобы получить внутреннюю версию MakeMeABlah, которая не выполняет повторную проверку в версии выпуска.

1 голос
/ 06 октября 2009

Официальные C # Рекомендации по проектированию говорят, что нужно выбросить исключение и позволить уровню пользовательского интерфейса обработать исключение.

0 голосов
/ 06 октября 2009

Зачем нужна кривая, если она недействительна? Используя шаблон построителя, вы можете предоставить возможность создавать только допустимые объекты Curve и позволить пользовательскому интерфейсу обрабатывать недопустимое состояние.

В этом (я думаю) суть предложения Эрика - раскрыть внешний способ проверки состояния перед созданием недопустимого объекта.

Примечание. После того, как ваше здание будет содержать только действительные объекты Curve, вы можете удалить страшный логический if-создает «bool BaseCurveIsValid». :)

...