Подтвердить что ты не робот

Перегрузка метода с дополнительным параметром в С# 4.0

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

Есть ли какая-то особенная вещь, которую вы должны учитывать при выборе необязательного параметра (или перегрузки)?

4b9b3361

Ответ 1

Одним из хороших вариантов использования "Необязательных параметров" в сочетании с "Именованными параметрами" в С# 4.0 является то, что он представляет собой изящную альтернативу перегрузке метода, где вы перегружаете метод, основанный на количестве параметров.

Например, вы хотите, чтобы метод foo вызывался/использовался так, foo(), foo(1), foo(1,2), foo(1,2, "hello"). С перегрузкой метода вы будете реализовывать такое решение,

///Base foo method
public void DoFoo(int a, long b, string c)
{
   //Do something
}  

/// Foo with 2 params only
public void DoFoo(int a, long b)
{
    /// ....
    DoFoo(a, b, "Hello");
}

public void DoFoo(int a)
{
    ///....
    DoFoo(a, 23, "Hello");
}

.....

С дополнительными параметрами в С# 4.0 вы бы использовали пример использования, как показано ниже:

public void DoFoo(int a = 10, long b = 23, string c = "Hello")

Затем вы можете использовать метод так: Обратите внимание на использование именованного параметра -

DoFoo(c:"Hello There, John Doe")

Этот вызов принимает значение параметра a как 10, а параметр b - 23. Другой вариант этого вызова - обратите внимание, что вам не нужно устанавливать значения параметров в порядке, как они появляются в сигнатуре метода, именованный параметр делает значение явным.

DoFoo(c:"hello again", a:100) 

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

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

Ответ 2

Необязательные параметры предоставляют проблемы, когда вы публично публикуете их как API. Переименование параметра может привести к проблемам. Изменение значения по умолчанию приводит к проблемам (см., Например, здесь для некоторой информации: Предостережения дополнительных параметров С# 4.0)

Кроме того, необязательные параметры могут использоваться только для констант времени компиляции. Сравните это:

public static void Foo(IEnumerable<string> items = new List<string>()) {}
// Default parameter value for 'items' must be a compile-time constant

к этому

public static void Foo() { Foo(new List<string>());}
public static void Foo(IEnumerable<string> items) {}
//all good

Update

Здесь некоторые дополнительные материалы для чтения, когда конструктор с параметрами по умолчанию не играет хорошо с Reflection.

Ответ 3

Это почти само собой разумеется, но:

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

Конечно, это даже не проблема для большинства магазинов. Но вы можете поспорить, почему Microsoft не использует дополнительные параметры в библиотеке базового класса.

Ответ 4

Я считаю, что они служат различным целям. Необязательные параметры: если вы можете использовать значение по умолчанию для параметра, а базовый код будет таким же:

public CreditScore CheckCredit( 
  bool useHistoricalData = false,  
  bool useStrongHeuristics = true) { 
  // ... 
}

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

public void SendSurvey(IList<Customer> customers, int surveyKey) {  
  // will loop and call the other one 
} 
public void SendSurvey(Customer customer, int surveyKey) {  
  ...  
}

(я писал об этом некоторое время назад здесь)

Ответ 5

Необязательные параметры должны быть последними. Таким образом, вы не можете добавить дополнительный параметр к этому методу, если он не является необязательным. Пример:

void MyMethod(int value, int otherValue = 0);

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

void MyMethod(int value, int otherValue = 0, int newParam = 0);

Если он не может быть факультативным, вам необходимо использовать перегрузку и удалить необязательное значение для 'otherValue'. Вот так:

void MyMethod(int value, int otherValue = 0);
void MyMethod(int value, int otherValue, int newParam);

Я предполагаю, что вы хотите сохранить порядок параметров одинаковым.

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

Обновление При вызове методов с дополнительными параметрами вы можете использовать именованные параметры следующим образом:

void MyMethod(int value, int otherValue = 0, int newValue = 0);

MyMethod(10, newValue: 10); // Here I omitted the otherValue parameter that defaults to 0

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

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

void MyMethod(int value, int otherValue)
{
   // Do the work
}

void MyMethod(int value)
{
   MyMethod(value, 0); // Do the defaulting by method overloading
}

Затем при вызове 'MyMethod' следующим образом:

MyMethod(100); 

Будет вызвано 2 вызовами метода. Но если вы используете необязательные параметры, существует только одна реализация "MyMethod" и, следовательно, только один вызов метода.

Ответ 6

Ни один из них не является окончательно "лучше", чем другой. У них обоих есть место написания хорошего кода. Необязательные параметры следует использовать, если параметры могут иметь значение по умолчанию. Перегрузка метода должна использоваться, когда разница в сигнатуре выходит за пределы не определяющих параметров, которые могли бы иметь значения по умолчанию (например, поведение отличается в зависимости от того, какие параметры переданы и которые остаются по умолчанию).

// this is a good candidate for optional parameters
public void DoSomething(int requiredThing, int nextThing = 12, int lastThing = 0)

// this is not, because it should be one or the other, but not both
public void DoSomething(Stream streamData = null, string stringData = null)

// these are good candidates for overloading
public void DoSomething(Stream data)
public void DoSomething(string data)

// these are no longer good candidates for overloading
public void DoSomething(int firstThing)
{
    DoSomething(firstThing, 12);
}
public void DoSomething(int firstThing, int nextThing)
{
    DoSomething(firstThing, nextThing, 0);
}
public void DoSomething(int firstThing, int nextThing, int lastThing)
{
    ...
}

Ответ 7

Хорошим местом для использования необязательного параметра является WCF, поскольку он не поддерживает перегрузку метода.

Ответ 8

Как насчет третьей опции: передать экземпляр класса со свойствами, соответствующими различным "необязательным параметрам".

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

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

Ответ 9

На самом деле это не ответ на исходный вопрос, а комментарий на @NileshGule answer, но:

a) У меня недостаточно очков репутации для комментариев

b) Несколько строк кода довольно трудно читать в комментариях

Nilesh Gule писал (а):

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

Это действительно неверно, вам все равно нужно проверить наличие нулей:

void DoSomething(string value = "") // Unfortunately string.Empty is not a compile-time constant and cannot be used as default value
{
  if(value == null)
    throw new ArgumentNullException();
}

DoSomething(); // OK, will use default value of ""
DoSomething(null); // Will throw

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

Ответ 10

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

Именованные параметры дают гибкость передачи значений параметров в любом порядке.

Ответ 11

Чтобы решить свой первый вопрос,

Почему большинство классов библиотеки MSDN используют перегрузка вместо необязательной параметры?

Это для обратной совместимости.

Когда вы открываете проект С# 2, 3.0 или 3.5 в VS2010, он автоматически обновляется.

Представьте себе неудобства, которые он создавал бы, если бы каждая из перегрузок, используемых в проекте, должна была быть преобразована в соответствие с соответствующим необязательным объявлением параметра.

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