2010-01-22 20 views
31

Jakie są pro/przeciw użycia słowa kluczowego params vs. Lista jako dane wejściowe do niektórych funkcji C#?C#: params keyword vs list

Przede wszystkim, jakie są względy związane z , i inne kompromisy.

Odpowiedz

33

Słowo kluczowe params jest cukier syntaktyczny obsługiwane przez kompilator C#. pod maską, to faktycznie toczenia

void Foo(params object[] a) { ... } 
Foo(1,2,"THREE"); 

do

void Foo(object[] a) { ... } 
Foo(new object[] { 1, 2, "THREE" }) 

Z wydajności perspektywy jakbyś prośbą o, wywołanie params jest po prostu szybciej, ponieważ jest to nieco szybciej tworzyć tablica niż do utworzenia listy <>. Nie ma różnicy w wydajności między dwoma opisami powyżej.

+0

Gdybyśmy przekazali istniejącą referencję do Listy, wolniej byłoby używać paramów ze względu na narzut przydzielania pamięci dla tablicy. –

+1

@Mert: Ale musisz też przydzielić pamięć dla listy <>, którą przekazujesz jako odniesienie ... –

+0

@ZeCarlos, ale założyłem, że lista już istnieje. –

2

Słowo kluczowe params pozwala dynamicznie przekazać zmienną liczbę argumentów funkcji bez obawy o błędy kompilatora, takich jak ten:

public string PrefixFormatString(string p, string s, params object[] par) 
{ 
    return p + string.Format(s, par); 
} 
... 
PrefixFormatString("COM", "Output Error #{0} - Error = {1}", errNum, errStr); 

Jeśli przekazać listę, trzeba skonstruować listę zanim można przekaż go:

public string PrefixFormatString(string p, string s, List<object> par) 
{ 
    return p + string.Format(s, par.ToArray()); 
} 
... 
List<object> l = new List<object>(new object[] { errNum, errStr }); 
PrefixFormatString("COM", "Output Error #{0} - Error = {1}", l); 

i ma tendencję do ukrywania znaczenia tego, jakiego rodzaju danych oczekuje funkcja.

Należy zauważyć, że jest to bardzo podobne do przekazywania prostej zmiennej tablicowej. Jedyną różnicą jest to, że kompilator ustawi parametry w tablicy dla ciebie ... Nie jestem w 100% pewny, ale myślę, że różnica techniczna jest po prostu syntaktycznym cukrem - w obu przypadkach tak naprawdę przekazujesz tablicę wpisz parametr jest.

+0

co o problemy z wydajnością? –

+2

To nie jest typ problemu, który naprawdę powinien martwić się wydajnością - jestem pewien, że w każdym, o czym myślisz, są znacznie większe problemy z hakowaniem wydajności. Wydajność jest praktycznie taka sama, ze względu na fakt (moim zdaniem), że jest to głównie składnia kompilatora i nie ma nic wspólnego z tym, jak sama funkcja jest wywoływana, gdy jest w IL. –

0

Cóż, z params słowo kluczowe można wprowadzić argumenty do metody jak ta:

MethodName(1, 2, 3, 4); 

Ale z listy, to zrobiłbym to tak:

MethodName(new List<int> {1, 2, 3, 4}); 

składnia może być bardziej wyraźnym w tym pierwszym niż drugim. Jest to przydatne, gdy trzeba tylko jeden parametr do przekazania w:

// params 
MethodName(1); 

// List 
MethodName(new List<int> {1}); 
+0

co z problemami z wydajnością? –

2

dobrze, params pozwala na ładniejsze składni podczas wywoływania go, ale lista (zakładając, że masz na myśli IList<>) jest bardziej elastyczny, ponieważ różne klasy mogą realizować Interfejs. Przekazywanie numeru List<> ma sens tylko wtedy, gdy konieczne jest wykonanie określonych operacji na liście, które nie są obsługiwane przez interfejs (na przykład ToArray()).

+0

co z problemami z wydajnością? –

+0

A co z nimi? –

+0

+1 dla IList lub innego odpowiedniego interfejsu w zależności od tego, co musi zrobić Twoja kolekcja. –

0

params to konstrukcja językowa dla funkcji pobierających zmienną liczbę parametrów. Jest podobny do specyfikatora C elipses - tj. printf(char* fmt, ...). Język obsługuje ten rodzaj operacji, może równie dobrze z niego korzystać, zwłaszcza jeśli ułatwia czytanie kodu.

0

Osobiście pominęłbym parametry. Zostałem ukąszony przez to raz lub dwa razy. W jaki sposób? Pozwól mi wyjaśnić.

napisać metodę publiczną z tym podpisem:

public static void LogInUser(string username, string password, params string[] options) 

przetestować go, to działa, jej zrobić ... i kolejny zespół/aplikacja jest wywołaniem funkcji.

Teraz, miesiąc później chcesz zmienić swój podpis, aby dodać rolę użytkownika:

public static void LogInUser(string username, string password, string role, params string[] options) 

Och, jak wiele się zmieniło niczego wywołującego metodę.

LogInUser("[email protected]", "zz", "Admin", "rememberMe", "800x600"); 
+0

Ponadto, params "pachnie" jak często używane w Interop. –

+4

Cóż, nie miałbyś tego problemu, jeśli zgrupujesz zdefiniowane elementy w jednym obiekcie, np. 'Credentials'. –

+1

Dynami, masz absolutną rację. Zły kod ... złe użycie parametrów. –

0

Główną różnicą między nimi, że widzę to, że liczba parametrów przekazywanych do metody jest ustawiony w czasie kompilacji używając params, natomiast z List<T> zależy na liście przyjętej w czasie wykonywania.

Czy ustalenie liczby argumentów, z którymi twoja metoda musi zostać wywołana w czasie kompilacji, to pro lub con, zależy całkowicie od twojego projektu i zamiaru. Może to być korzyść zależna od tego, co masz nadzieję osiągnąć.

Params pomaga na front czytelności i jest tak blisko parametru opcjonalnego, że dostaniesz się do C#. Osobiście używałbym tylko implementacji List<T>, gdybym potrzebował zużyć nieznaną liczbę parametrów w dowolnym punkcie.

Edytuj: po prostu zauważyłeś swoją zmianę dotyczącą problemów z wydajnością. Na ten temat nie jestem pewien, chociaż gdybyś mógł oczekiwać dużej liczby "parametrów" przy użyciu List<T>, podczas gdy params ma limit na zdrowie psychiczne ze względu na konieczność ich kodowania.

23

Osobiście używam params pisząc funkcje, które mają szereg wejść świadczonych przez inny programista (np String.Format) i IEnumerable pisząc funkcje, które mają listę elementów danych dostarczonych przez komputer (na przykład File.Write).

Wpływ na wydajność jest znikomy. Martwiąc się o wykonanie tak trywialnej rzeczy, jak to jest dokładnie o czym Donald Knuth mówił w słynnym cytacie "przedwczesna optymalizacja jest źródłem wszelkiego zła".

Powiedział, że pytający zdaje się kojarzy się wyłącznie na tym, więc proszę bardzo:

wyników dla 10 milionów iteracji:

params took 308 ms 
list took 879 ms 

Z tych wyników widać, że tablica params jest po prostu ponad dwa razy szybciej. Prosty fakt, że możesz zadzwonić do którejkolwiek z tych rzeczy pod sekundą oznacza, że ​​całkowicie marnujesz swój czas, martwiąc się o to. Użyj wszystkiego, co pasuje do twojego kodu, najlepiej.

Kod go przetestować (skompilowany i uruchomić w trybie uwolnienia używając VS2008)

class Program 
{ 
    const int COUNT = 10000000; 

    static IEnumerable<string> m_value = null; 

    static void ParamsMethod(params string[] args) 
    { m_value = args; } // do something with it to stop the compiler just optimizing this method away 

    static void ListMethod(List<string> args) 
    { m_value = args; } // do SOMETHING with it to stop the compiler just optimizing this method away 

    static void Main(string[] args) 
    { 
     var s = new Stopwatch(); 
     s.Start(); 
     for (int i = 0; i < COUNT; ++i) 
      ParamsMethod("a", "b", "c"); 

     Console.WriteLine("params took {0} ms", s.ElapsedMilliseconds); 

     s.Reset(); 
     s.Start(); 
     for (int i = 0; i < COUNT; ++i) 
      ListMethod(new List<string> { "a", "b", "c" }); 

     Console.WriteLine("list took {0} ms", s.ElapsedMilliseconds); 
    } 
} 
+0

Dzieje się tak, ponieważ czas tworzenia listy jest powolny. jeśli wywołasz metodę, która pobiera IEnumerable powiedzmy, ciąg [] zamiast listy wydajność byłaby prawie równoważna z metodą params. – Jimmy

+10

Pewnie, ale to nie ma znaczenia! –

0

Wydajność programatora Wywołanie metody może być czasem poprawione przez użycie słowa kluczowego params.

(Zważywszy, że programiści kosztować tak dużo więcej niż komputerów, dlaczego myślisz jakiegokolwiek innego rodzaju świadczenia.)