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.
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.
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.
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.
co o problemy z wydajnością? –
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. –
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});
co z problemami z wydajnością? –
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()
).
co z problemami z wydajnością? –
A co z nimi? –
+1 dla IList
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.
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");
Ponadto, params "pachnie" jak często używane w Interop. –
Cóż, nie miałbyś tego problemu, jeśli zgrupujesz zdefiniowane elementy w jednym obiekcie, np. 'Credentials'. –
Dynami, masz absolutną rację. Zły kod ... złe użycie parametrów. –
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.
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);
}
}
Dzieje się tak, ponieważ czas tworzenia listy jest powolny. jeśli wywołasz metodę, która pobiera IEnumerable powiedzmy, ciąg [] zamiast listy
Pewnie, ale to nie ma znaczenia! –
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.)
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. –
@Mert: Ale musisz też przydzielić pamięć dla listy <>, którą przekazujesz jako odniesienie ... –
@ZeCarlos, ale założyłem, że lista już istnieje. –