overloading metody vs opcjonalny parametr w C # 4.0 [duplikat]

To pytanie ma już odpowiedź tutaj:

Który jest lepszy? na pierwszy rzut oka opcjonalny parametr wydaje się lepszy (mniej kodu, mniej dokumentacji XML, itp.), Ale dlaczego większość klas biblioteki MSDN używa przeciążenia zamiast opcjonalnych parametrów?

Jest czy jest jakaś specjalna rzecz, którą musisz wziąć pod uwagę, gdy zdecydujesz się użyć opcjonalnego parametru (lub przeciążenia)?

Author: Louis Rhys, 2010-07-23

11 answers

Jednym z dobrych przykładów użycia 'opcjonalnych parametrów' w połączeniu z' nazwanymi parametrami ' w C# 4.0 jest to, że przedstawia nam elegancką alternatywę dla metody przeciążania, gdzie przeciążamy metodę na podstawie liczby parametrów.

Na przykład powiedz, że chcesz, aby metoda foo była wywoływana / używana w ten sposób, foo(), foo(1), foo(1,2), foo(1,2, "hello"). Z przeciążeniem metody zaimplementowałbyś takie rozwiązanie,

///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");
}

.....

Z opcjonalnymi parametrami w C # 4.0 można zaimplementować użycie przypadek jak poniżej,

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

Wtedy możesz użyć metody w ten sposób-zwróć uwagę na użycie nazwanego parametru -

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

To wywołanie przyjmuje parametr a wartość jako 10, a parametr b jako 23. Inny wariant tego wywołania-zauważ, że nie trzeba ustawiać wartości parametrów w kolejności, w jakiej występują w sygnaturze metody, nazwany parametr sprawia, że wartość jest jawna.

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

Kolejną zaletą użycia nazwanego parametru jest to, że znacznie zwiększa czytelność i w ten sposób zachowanie kodu opcjonalnych metod parametrycznych.

Zauważ, że jedna metoda sprawia, że potrzeba zdefiniowania 3 lub więcej metod w method overloading. To, co znalazłem, jest dobrym przykładem użycia opcjonalnego parametru w połączeniu z nazwanymi parametrami.

 74
Author: Bikal Lem,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-23 15:21:28

Opcjonalne parametry stwarzają problemy, gdy ujawniasz je publicznie jako API. Zmiana nazwy parametru może prowadzić do problemów. Zmiana wartości domyślnej prowadzi do problemów (patrz np. tutaj, aby uzyskać pewne informacje: zastrzeżenia W C# 4.0 opcjonalne parametry)

Również opcjonalne paramy mogą być używane tylko dla stałych czasu kompilacji. Porównaj to:

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

Do tego

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

Update

Oto dodatkowy materiał do czytania, gdy konstruktor z domyślnymi parametrami robi nie baw się dobrze z refleksją .

 53
Author: flq,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-22 15:29:32

Wierzę, że służą innym celom. Parametry opcjonalne są wtedy, gdy można użyć wartości domyślnej dla parametru, a kod podstawowy będzie taki sam:

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

Przeciążenia metody są dla sytuacji, gdy masz wzajemnie wykluczające się (podzbiory) parametrów. Zwykle oznacza to, że musisz wstępnie przetworzyć niektóre parametry lub że masz inny kod dla różnych "wersji" metody (zauważ, że nawet w tym przypadku niektóre parametry mogą być współdzielone, dlatego wymienione powyżej" podzbiory"):

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

(pisałem o tym jakiś czas temu tutaj )

 32
Author: Jordão,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-12 09:17:55

To prawie oczywiste, ale:

Nie wszystkie języki obsługują opcjonalne parametry. Jeśli chcesz, aby Twoje biblioteki były przyjazne dla tych języków, musisz użyć przeciążeń.

Przyznam, że to nie jest nawet problem dla większości sklepów. Ale można się założyć, że to dlatego Microsoft nie używa opcjonalnych parametrów w bibliotece klas bazowych.

 27
Author: Joe White,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-23 13:08:03

Opcjonalne parametry muszą być ostatnie. Nie można więc dodać dodatkowego parametru do tej metody, chyba że jest ona również opcjonalna. Ex:

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

Jeśli chcesz dodać nowy parametr do tej metody bez przeciążania, musi być opcjonalny. Like this

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

Jeśli nie może być opcjonalne, wtedy należy użyć przeciążenia i usunąć opcjonalną wartość 'otherValue'. Tak:

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

Zakładam, że chcesz, aby kolejność parametrów była taka sama.

Więc używając opcjonalne parametry zmniejszają liczbę metod, które musisz mieć w swojej klasie, ale są ograniczone tym, że muszą być ostatnie.

Update Podczas wywoływania metod z opcjonalnymi parametrami, można użyć nazwanych parametrów w następujący sposób:

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

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

Więc opcjonalne parametry dają rozmówcy więcej możliwości.

Ostatnia rzecz. Jeśli używasz metody overloading z jedną implementacją, w ten sposób:
void MyMethod(int value, int otherValue)
{
   // Do the work
}

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

Wtedy, gdy wywołujesz 'MyMethod' w ten sposób:

MyMethod(100); 

Will wynik w 2 wywołaniach metody. Ale jeśli używasz opcjonalnych parametrów, to jest tylko jedna implementacja 'MyMethod' i stąd tylko jedno wywołanie metody.

 9
Author: Martin Ingvar Kofoed Jensen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-23 08:42:08

Żadna z nich nie jest definitywnie "lepsza" od drugiej. Oboje mają swoje miejsce w pisaniu dobrego kodu. Parametry opcjonalne powinny być używane, jeśli parametry mogą mieć wartość domyślną. Przeciążenie metody powinno być stosowane, gdy różnica w podpisie wykracza poza to, że nie zdefiniowano parametrów, które mogłyby mieć wartości domyślne (np. zachowanie różni się w zależności od tego, które parametry są przekazywane, a które pozostawione domyślnym).

// 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
Author: Michael Meadows,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-15 11:25:06

Dobrym miejscem do użycia opcjonalnego parametru jest WCF , ponieważ nie obsługuje on metody przeciążania.

 4
Author: ashraf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-18 16:22:45

A co z trzecią opcją: przekazać instancję klasy o właściwościach odpowiadających różnym "opcjonalnym parametrom".

Daje to takie same korzyści jak parametry nazwane i opcjonalne, ale uważam, że często jest to znacznie jaśniejsze. Daje to możliwość logicznego pogrupowania parametrów w razie potrzeby (tj. z kompozycją) i hermetyzacji niektórych podstawowych walidacji.

Również, jeśli oczekujesz od klientów, którzy wykorzystują Twoje metody do wykonywania wszelkiego rodzaju metaprogramowania (np. budowanie wyrażeń linq z wykorzystaniem Twoich metod), myślę, że utrzymywanie prostego podpisu metody ma swoje zalety.

 2
Author: Michael Petito,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-23 16:19:42

To nie jest tak naprawdę odpowiedź na pierwotne pytanie, ale raczej komentarz do odpowiedzi @NileshGule , ale:

A) nie mam wystarczającej ilości punktów reputacji, aby skomentować

B) wiele linii kodu jest dość trudne do odczytania w komentarzach

Nilesh Gule napisał (a):

Jedną z zalet używania opcjonalnych parametrów jest to, że nie musisz sprawdzać warunkowo w metodach, np. czy łańcuch znaków był null lub pusty, jeśli jeden z parametrów wejściowych był łańcuchem znaków. Jako do opcjonalnego parametru zostanie przypisana wartość domyślna, kodowanie defensywne zostanie w znacznym stopniu zredukowane.

To jest rzeczywiście niepoprawne, musisz jeszcze sprawdzić czy nie ma 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

Jeśli podasz null string reference, nie zostanie ona zastąpiona wartością domyślną. Więc nadal musisz sprawdzić parametry wejściowe dla null.

 2
Author: Anlo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:48

Jedną z zalet używania opcjonalnych parametrów jest to, że nie musisz sprawdzać warunkowo w metodach, np. czy łańcuch znaków był null lub pusty, jeśli jeden z parametrów wejściowych był łańcuchem znaków. Ponieważ do opcjonalnego parametru zostanie przypisana wartość domyślna, kodowanie defensywne zostanie znacznie zredukowane.

Nazwane parametry dają elastyczność przekazywania wartości parametrów w dowolnej kolejności.

 1
Author: Nilesh Gule,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-23 11:30:15

Aby odpowiedzieć na twoje pierwsze pytanie,

Dlaczego większość klas biblioteki MSDN używa przeciążenie zamiast opcjonalnego parametry?

Służy do wstecznej kompatybilności.

Kiedy otwierasz projekt C# 2, 3.0 lub 3.5 W VS2010, jest on automatycznie aktualizowany.

Wyobraź sobie, jakie niedogodności spowodowałyby, gdyby każde przeciążenie użyte w projekcie musiało zostać przekonwertowane tak, aby pasowało do odpowiedniej opcjonalnej deklaracji parametrów.

Poza tym, jako powiedzenie mówi: "po co naprawiać to, co nie jest zepsute?". Nie jest konieczne zastępowanie przeciążeń, które już działają z nowymi implementacjami.

 0
Author: Alex Essilfie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-23 15:55:37