перегрузка метода против необязательного параметра в C# 4.0 [дубликат]



этот вопрос уже есть ответ здесь:



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



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

663   11  

11 ответов:

один хороший вариант использования "необязательных параметров" в сочетании с "именованными параметрами" в C# 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");
}

.....

С дополнительными параметрами в C# 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) 

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

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

Дополнительные параметры предоставляют проблемы, когда вы предоставляете их публично как API. Переименование параметра может привести к проблемам. Изменяя значение по умолчанию приводит к проблемам (см., например, следующую информацию: предостережения о дополнительных параметрах C# 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

обновление

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

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

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) {  
  ...  
}

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

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

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

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

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" и, следовательно, только один вызов метода.

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

// 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)
{
    ...
}

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

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

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

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

это на самом деле не ответ на исходный вопрос, а скорее комментарий к @Nileshgule's ответ, но:

a) у меня недостаточно очков репутации, чтобы комментировать

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

Nilesh Гуле писал:

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

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

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

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

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

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

чтобы ответить на ваш первый вопрос,

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

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

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

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

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

Comments

    Ничего не найдено.