2015-03-08 12 views
5


W języku C#, lambda może uzyskać dostęp do zmiennej lokalnej, a także zwrócić niektóre dane.C# lambda, przypisz lokalną zmienną do danych zwrotnych

, co jest lepsze w tej sytuacji?

int num; 
Func<int> func =()=>{return 10;} 
num = func(); 

vs

int num; 
Action action =()=>{num = 10;} 

myślę, wydajność jest różna. Co jest lepsze?



AKTUALIZACJA (nie wiem jak używać StackOverflow)

mój kod tutaj.

ErrorCode errorCode; 
errorCode = DatabaseUtility.Read<ErrorCode>(
    conn, 
    DatabaseUtility.CreateSelectQuery(....), 
    reader => 
    { 
     if(reader.Read()) 
      return ErrorCode.None; 

     return ErrorCode.InvalidParam; 
    }); 

Ale w takim przypadku mogę być w stanie to zrobić.

ErrorCode errorCode; 
DatabaseUtility.Read(
    conn, 
    DatabaseUtility.CreateSelectQuery(....), 
    reader => 
    { 
     if(reader.Read()) 
      errorCode = ErrorCode.None; 
     else 
      errorCode = ErrorCode.InvalidParam; 
    }); 

I to jest definicja metody.

public static class DatabaseUtility 
{ 
    public static Read<T>(
     MySqlConnection conn, 
     string query, 
     Func<MySqlDataReader, T> callback); 
} 
+1

co próbujesz osiągnąć? co rozumiesz przez _better_? co powstrzymuje cię od bezpośredniego przypisania '10' do' num'? –

+0

@ Selman22 o co pytasz? to tylko prosty przykład. Jeśli chcesz wiedzieć, dlaczego chcę poznać tę wiedzę, to mogę ci powiedzieć. Próbuję WYBRAĆ niektóre dane z mojego DB i obsłużyć dane. W tym celu definiuję metodę użyteczną z parametrem typu Func. I przetwarzam moje dane po metodzie narzędzia, więc Func zwraca moje dane. ale lambda może uzyskać dostęp do zmiennej lokalnej, dlaczego zwracam moje dane? Mogę przypisać moje dane do mojej lokalnej zmiennej. prawda? więc pytam, który jest lepszy kod. –

+0

Co sprawia, że ​​uważasz, że wydajność jest inna? Czy twoja aplikacja jest tak doskonała, że ​​musisz martwić się o taką mikrooptymalizację? –

Odpowiedz

2

Pierwszy z nich jest lepiej zaprojektowany. Jest on wielokrotnego użytku i może być wywoływany wielokrotnie na różnych zmiennych (jeśli jest to wymagane).

Osiągi, których nie jestem pewien, najprawdopodobniej nieistotne.

+0

+1 za możliwość ponownego użycia. IMHO dobrze napisane oprogramowanie jest warte więcej niż nieco bardziej wydajne blokowanie. W twoim kodzie zajmujesz się DB, co zwykle zajmuje dużo więcej czasu niż niektóre operacje C#. 100% głosów na cokolwiek jest łatwe do odczytania, utrzymania i być może zgodne z wzorami GOF: http://en.wikipedia.org/wiki/Design_Patterns –

4

Gibbo ma rację: zwracanie wartości jest bardziej wyraźne, więc powinieneś tego użyć i nie martwić się wydajnością, chyba że ten kod jest w the 3% of code when microoptimizations make sense.

Ale zwracanie może być również bardziej efektywne, ponieważ nie wymaga przydziału sterty dla obiektu zamknięcia, a ponieważ oznacza to, że num zostanie skompilowany jako zmienna lokalna, a nie pole obiektu zamknięcia (dostęp do lokalnego zmienne są tańsze niż pola).

Ponadto, jeśli masz zamiar zwrócić wartość, nie ma powodu, aby zadeklarować zmienną tak wcześnie, co uczyni Twój kod nieznacznie krótsza:

Func<int> func =()=>{return 10;} 
int num = func(); 
+0

jeśli używam zmiennej lokalnej w lambda, zmienna została zmieniona jak zmienna członka? Mój zaktualizowany kod nie jest inny? Jeśli używam tego samego kodu więcej niż raz, to za każdym razem zwraca dane lambda, nieprawdaż? ale jeśli mam dostęp do tej samej zmiennej lokalnej (może być zmienione pole), jest tylko jedno pole. który z nich pokazuje mi lepszą wydajność? Wiem, że to bardzo, bardzo, bardzo mała różnica. Po prostu się nad tym zastanawiam. –

+0

Tak, przy zaktualizowanym kodzie nadal jest taki sam. A jeśli użyjesz tego samego więcej niż raz, to jest to wciąż to samo: tworzenie obiektu zamknięcia i dostęp do pola będzie droższy niż nie tworzenie obiektu i uzyskiwanie dostępu do zmiennej lokalnej. – svick

+0

Jeśli tworzę na lambda i wywołuję, ** obiekt zamknięcia ** jest tworzony za każdym razem? jeśli nie, ** koszt powrotu ** każdego wezwanego czasu jest droższy niż ** stworzony obiekt zamknięcia **, czyż nie? następnie, Czy mogę zrozumieć, że ** obiekt zamknięcia ** jest tworzony za każdym razem, gdy ponownie wywołać func()? –

1

Właściwie istnieje duża różnica semantyczne.

() => 10; 
() => x = 10; 

Zarówno powrócić 10. Różnica polega na tym, że w drugim przypadku zmienna x zostaje schwytany, związany z ciałem Lamba i mogą podróżować przez kontekstach.

Imagine:

void SomeFunction() 
{ 
    int variable; 
    Execute((a) => variable = a); 
} 

void Execute(Action<int> statement) 
{ 
    statement.Invoke(7); 
} 

Tutaj SomeFunc nie ma pojęcia, jaka jest wartość zmiennej będzie przy wyjściu z kontekstu funkcji. Z drugiej strony Execute nie ma pojęcia, co stanie się z wartością przekazaną do obiektu funkcji przez Invoke. Może to być przydatne w niektórych kontekstach enkapsulacji. A może w sytuacjach, w których trafisz na limity generyczne C# (co jest bardzo łatwe przy okazji).

Możesz myśleć w obie strony, jeśli chodzi o kod. na przykład"Czy chcę obsłużyć błędy po mojej stronie, czy też udostępnić użytkownikowi mojego interfejsu sposób obsługi błędów?"

Ale wtedy wolałbym użyć klasy abstrakcyjnej do wdrożenia/wymuszenia wyżej wspomnianego zachowania zamiast lambd.

Ogólnie mówiąc, wysyłanie przechwyconych zmiennych w kontekstach wydaje się ukrywać zależności i sprawia, że ​​kod jest trudniejszy (w niektórych przypadkach nawet niemożliwy) do czytania i debugowania. Myślę, że powinno to być używane tylko w scenariuszach, gdzie wszystkie inne środki C# dają bardzo powolny lub bardzo brzydki kod.

+0

Nie ma dokładnie tego, co dokładnie wędruję. I nie znam twojego punktu, ponieważ mój angielski jest zły. masz na myśli, że nie używasz lambda? –

+0

Nie, używaj lambda. Ale unikaj przechwytywania zmiennych, chyba że jest to konieczne lub trywialne. –

+0

** zmienne przechwycone ** oznaczają zmienne lokalne spoza lambda? –

1

Chcę podnieść mały problem z kodem ty Wysłany:

public static class DatabaseUtility 
{ 
    public static Read<T>(
     MySqlConnection conn, 
     string query, 
     Func<MySqlDataReader, T> callback); 
} 

metoda ma podpis typu powrót! czy to jest puste? Jeśli jest nieważny kod zostanie zaksięgowana nie zadziała:

ErrorCode errorCode; 
errorCode = DatabaseUtility.Read<ErrorCode>(
    conn, 
    DatabaseUtility.CreateSelectQuery(....), 
    reader => 
    { 
     if(reader.Read()) 
      return ErrorCode.None; 

     return ErrorCode.InvalidParam; 
    }); 

jeśli jest T już wtedy nie ma potrzeby deklarowania Func aby przejść do funkcji czytania.

Myślę, że w tym przypadku zwracana jest wartość funkcji Read, która powinna być T, i biorąc pod uwagę, że chcesz wykonać działanie z typem danych, który pobierasz (w przypadku jakiegoś błędu lub w innym przypadku), lepiej zdać działania zamiast:

public static class DatabaseUtility 
{ 
    public static T Read<T>(
     MySqlConnection conn, 
     string query, 
     Action<MySqlDataReader> callback); 
} 

założeniu, że Wydajność mądry to nie powinno być problemem, jeśli nie są kierowane do stosowania w czasie rzeczywistym (co moim zdaniem to nie twoja sprawa). Jednak byłoby to lepsze rozwiązanie IMHO.

nadzieję, że to pomaga.

+0

brak typu zwrotu w moim poście to mój błąd. Alos Read metoda zawiera 'return callback (MySqlDataReaderInstance);' –

Powiązane problemy