Как я могу получить из двух базовых конструкторов таким образом, чтобы я мог иметь значения аргументов по умолчанию? - PullRequest
0 голосов
/ 13 января 2019

Я пишу исключение, которое наследуется от ArgumentOutOfRangeException, и я хочу написать конструкторы, которые наследуются от двух базовых перегрузок: base (string paramName) и base (string paramName, string message), но я хочу предоставить значения по умолчанию для paramName в оба конструктора и значение по умолчанию для сообщения во втором. Каков наилучший способ сделать это? (Если это поможет, значение по умолчанию для paramName будет одинаковым в обоих).

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

Вот пример того, что я пытаюсь сделать:

public class TrainingSetCardinalityMismatch : ArgumentOutOfRangeException
{
    public TrainingSetCardinalityMismatch(string paramName = "trainingSets") : base(paramName)
    {
        //code here
    }
    public TrainingSetCardinalityMismatch(string paramName = "trainingSets", message = "Number of training sets provided must match number of answers provided") : base(paramName, message)
    {
        //code here
    }
}

Ответы [ 4 ]

0 голосов
/ 13 января 2019

Ну, от вопроса, я вижу 2 варианта.

  • Вы всегда хотите сообщение (второй аргумент)
  • Вам иногда нужно сообщение, иногда нет, а иногда другое сообщение.

В первом случае вы просто удалили бы определение первого конструктора. У вас всегда будет сообщение, если вы не укажете второй аргумент.

public class TrainingSetCardinalityMismatch : ArgumentOutOfRangeException
{
    public TrainingSetCardinalityMismatch(
            string paramName = "trainingSets", 
            message = "Number of training sets provided must match number of answers provided") 
        : base(paramName, message)
    {
        //code here
    }
}

Тогда вы могли бы назвать это так:

// default param name + default message
throw new TrainingSetCardinalityMismatch(); 

// custom param, default message
throw new TrainingSetCardinalityMismatch("custom param"); 

// custom param, custom message
throw new TrainingSetCardinalityMismatch("custom param", "custom message"); 

Однако он не позволяет использовать параметры по умолчанию, но с пользовательским сообщением.

Если вы хотите этого, у вас есть несколько возможностей:

  • Можно было бы иметь константу для сообщения по умолчанию и указать ее явно вместо жестко закодированной строки.
  • Другим может быть изменение порядка параметров, если большую часть времени необходимо настраивать сообщение.
  • Еще один вариант - иметь статические функции, вызывающие исключение.
  • Еще один вариант - установить значение по умолчанию, равное нулю, если при указании значения, равного нулю, заменить на значение по умолчанию. Таким образом, вы можете использовать пустую строку, если вы действительно не хотите сообщений.
  • Еще один - иметь 2 класса исключений (скажем, TrainingSetCardinalityMismatchA and TrainingSetCardinalityMismatchB`), и у каждого из них есть один конструктор.
  • Другим желанием будет использование enum вместо строки при использовании предопределенных сообщений, и тогда конструктор с настраиваемым сообщением не будет иметь никакого значения по умолчанию, так как он будет использоваться только для конкретного сообщения.

Обычно я предпочитаю последний способ, и тогда я мог бы использовать ресурс и немного кода, чтобы загрузить соответствующую строку из идентификатора enum, что относительно просто в C #, так как вы можете enum_var.ToString() получить имя и используйте это имя для загрузки ресурса по его имени с помощью диспетчера ресурсов (см. https://docs.microsoft.com/en-us/dotnet/api/system.resources.resourcemanager?view=netframework-4.7.2).

0 голосов
/ 13 января 2019

Почему бы не создать свои собственные конструкторы и не вызывать базовые, как показано ниже

class MyArgumentOutOfRangeException : ArgumentOutOfRangeException
{
    public MyArgumentOutOfRangeException(string myName):base("PlaceDefaultNamepropValue")
    {
        // do something with passed my name
    }
    public MyArgumentOutOfRangeException(string myname, string mymessage):base("PlaceDefaultNamepropValue", "PlaceDefaultMessagepropValue")
    {
        // do something with passed my name
        // do something with passed my message
    }
}


class MyOtherArgumentOutOfRangeException : ArgumentOutOfRangeException
{
    public MyOtherArgumentOutOfRangeException(string myName) : this("PlaceDefaultNamepropValue",string.Empty)
    {
        // do something with passed my name
    }
    public MyOtherArgumentOutOfRangeException(string myname, string mymessage) : base("PlaceDefaultNamepropValue", "PlaceDefaultMessagepropValue")
    {
        // do something with passed my name
        // do something with passed my message
    }
}
0 голосов
/ 13 января 2019

Кроме необходимости определения типа message (используйте string message = "..."), ваш опубликованный код, кажется, работает и выполняет то, что вы хотите. Итак, я предполагаю, что суть вашего вопроса:

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

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

  1. Параметры со значениями по умолчанию являются по определению необязательными параметрами. Это означает, что вы уже можете выбирать выбор конструктора вашего потребителя на основе того, передал ли потребитель значение не по умолчанию message. Если они этого не сделали, то они явно выбрали первый вариант. Если они это сделали, то они явно выбирают второй вариант. Им не нужно также указывать логическое значение.
  2. Действительно ли имеет значение, не инициализируете ли вы сообщение или вместо этого явно передаете null или String.empty, когда потребитель не предоставляет значение сообщения? Потому что если нет, то нет никаких оснований даже пытаться различать два базовых конструктора.
  3. Перегрузка метода по своей природе существует, чтобы дать пользователям возможность различать различные наборы входных параметров, и каждое перегруженное тело имеет свой собственный метод (который вы можете выбрать для цепочки или нет), так что вы имеете полный контроль над тем, что происходит в этом случае , Ваше логическое значение будет (IMO бедным) заменой более чистой перегрузки метода.
  4. Логические значения CYOA имеют тенденцию казаться жизнеспособными только тогда, когда вы используете свой собственный код, потому что «я знаю, как я разработал это для работы». Это часто то, что приводит к отказу от хорошей практики и чистого кодирования. Хотя он будет работать на техническом уровне, он не является хорошим / чистым решением и в конечном итоге учит плохим привычкам. В большинстве случаев, когда я использую чужую библиотеку, я ожидаю использовать имена методов, чтобы решить, что я хочу сделать, а не набор логических параметров. Конечно, есть исключения, но они немногочисленны. Когда я выбрал метод, который нужно использовать, параметры должны быть простыми для понимания и предоставления, а не заставлять пользователя выбирать отдельные варианты поведения.
  5. Инкапсуляция предполагает, что ваша реализация должна скрывать сложности от потребителя вашего класса, где это возможно. Это означает, что вам разрешено использовать разветвленную структуру внутри вашего класса, но вы не должны требовать, чтобы потребитель сознательно сделал этот выбор - ваш класс существует, чтобы сделать это для потребителя и упростить рабочую нагрузку потребителя. Если вы передадите деньги своему потребителю, то какова ценность вашего класса? Что это делает для вас / конечного пользователя? (Примечание. Не следует неверно истолковывать это как аргумент против IOC. IOC - это хорошо, просто это не делается с помощью логических значений. Используя IOC, вы будете вводить объекты поведения вместо логических значений).
0 голосов
/ 13 января 2019

Вы можете вызвать другой конструктор со значениями по умолчанию, например,

public CustomException(string paramName = "defaultName") : this(paramName, null)
{
}

public CustomException(string paramName = "defaultName", string message = "defaultMessage") : base(paramName, message)
{
}
...