Czy funkcje powinny zwracać null czy pusty obiekt?

Jaka jest najlepsza praktyka podczas zwracania danych z funkcji. Czy lepiej zwrócić Null czy pusty obiekt? I dlaczego jedno ma robić jedno nad drugim?

Rozważ to:

public UserEntity GetUserById(Guid userId)
{
     //Imagine some code here to access database.....

     //Check if data was returned and return a null if none found
     if (!DataExists)
        return null; 
        //Should I be doing this here instead? 
        //return new UserEntity();  
     else
        return existingUserEntity;
}

Udawajmy, że w tym programie będą ważne przypadki, że nie będzie informacji o użytkowniku w bazie danych z tym identyfikatorem GUID. Wyobrażam sobie, że nie wypadałoby w tym przypadku wprowadzić wyjątku?? Również mam wrażenie, że obsługa wyjątków może hurt performance.

Author: 7wp, 2009-10-26

30 answers

Zwracanie null jest zwykle najlepszym pomysłem, jeśli zamierzasz wskazać, że żadne dane nie są dostępne.

Pusty obiekt oznacza, że dane zostały zwrócone, podczas gdy zwracanie null wyraźnie wskazuje, że nic nie zostało zwrócone.

DODATKOWO, zwrócenie null spowoduje wyjątek null, jeśli spróbujesz uzyskać dostęp do członków obiektu, co może być przydatne do podświetlania błędnego kodu - próba uzyskania dostępu do członka nothing nie ma sensu. Dostęp do elementów składowych pustego obiektu nie zawiedzie, co oznacza, że błędy mogą pozostać nieodkryte.

 208
Author: ljs,
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
2009-11-26 07:08:12

To zależy od tego, co ma największy sens w twojej sprawie.

Czy ma sens zwracanie null, np. "no such user exists"?

Czy ma sens tworzenie domyślnego użytkownika? Ma to największy sens, gdy można bezpiecznie założyć, że jeśli użytkownik nie istnieje, kod wywołujący zamierza istnieć, gdy o to poprosi.

Czy ma sens rzucanie wyjątku (a la "FileNotFound"), jeśli kod wywołujący wymaga użytkownika o nieprawidłowym identyfikatorze?

Jednak - z oddzielenia trosk / SRP punktu widzenia, pierwsze dwa są bardziej poprawne. I technicznie pierwszy jest najbardziej poprawny ( ale tylko przez włos) - GetUserById powinien być odpowiedzialny tylko za jedną rzecz - pozyskanie użytkownika. Obsługa własnego przypadku "Użytkownik nie istnieje" poprzez zwrócenie czegoś innego może być naruszeniem SRP. Rozdzielenie na inne sprawdzenie - bool DoesUserExist(id) byłoby właściwe, jeśli zdecydujesz się rzucić wyjątek.

Na podstawie obszernych komentarzy poniżej : jeśli jest to pytanie projektowe na poziomie API, ta metoda może być analogiczna do "OpenFile" lub "ReadEntireFile". "Otwieramy" użytkownika z jakiegoś repozytorium i uwodniamy obiekt z wynikowych danych. Wyjątek może być odpowiedni w tym przypadku. Może nie, ale może być.

Wszystkie podejścia są akceptowalne-to zależy tylko od większego kontekstu API/aplikacji.

 44
Author: Rex M,
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
2009-10-26 19:33:42

Osobiście używam NULL. Wyraźnie widać, że nie ma żadnych danych do zwrotu. Są jednak przypadki, gdy obiekt Null może być użyteczny.

 30
Author: Fernando,
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
2009-10-26 18:48:32

Jeśli zwracany typ jest tablicą, to zwraca pustą tablicę, w przeciwnym razie zwraca null.

 27
Author: Darin Dimitrov,
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
2009-10-26 18:48:49

Należy wyrzucić wyjątek (tylko), jeśli konkretna umowa jest złamana.
W konkretnym przykładzie, prosząc o UserEntity na podstawie znanego identyfikatora, zależy to od faktu, czy brakujący (usunięci) użytkownicy są oczekiwanym przypadkiem. Jeśli tak, to return null ale jeśli nie jest to oczekiwany przypadek, to rzuć wyjątek.
Zauważ, że jeśli funkcja została wywołana UserEntity GetUserByName(string name), prawdopodobnie nie rzuciłaby, ale zwróciła null. W obu przypadkach zwracanie pustego użytkownika byłoby nieprzydatne.

Dla ciągów, tablice i zbiory sytuacja jest zwykle inna. Pamiętam pewne wytyczne z MS, że metody powinny akceptować null jako' pustą ' listę, ale zwracają zbiory o zerowej długości, a nie null. To samo dotyczy sznurków. Zauważ, że możesz zadeklarować puste tablice: int[] arr = new int[0];

 12
Author: Henk Holterman,
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
2009-10-26 22:20:16

Jest to pytanie biznesowe, zależne od tego, czy istnienie użytkownika o określonym identyfikatorze Guid jest oczekiwanym normalnym przypadkiem użycia tej funkcji, czy też jest to anomalia, która uniemożliwi aplikacji pomyślne ukończenie dowolnej funkcji, której ta metoda dostarcza obiekt użytkownikowi...

Jeśli jest to "wyjątek", ponieważ brak użytkownika o tym identyfikatorze uniemożliwi aplikacji pomyślne wypełnienie dowolnej funkcji, którą wykonuje, (powiedzmy, że tworzymy faktura dla Klienta, do którego wysłaliśmy produkt...), wtedy ta sytuacja powinna rzucić ArgumentException (lub jakiś inny niestandardowy wyjątek).

Jeśli brakujący użytkownik jest ok, (jeden z potencjalnych normalnych wyników wywołania tej funkcji) zwróci null....

EDIT: (do komentarza Adama w innej odpowiedzi)

Jeśli aplikacja zawiera wiele procesów biznesowych, z których jeden lub więcej wymaga od użytkownika pomyślnego zakończenia, a jeden lub więcej z nich może zakończyć się pomyślnie bez użytkownika, wtedy wyjątek powinien być wyrzucany dalej w górę stosu wywołań, bliżej miejsca, w którym procesy biznesowe wymagające użytkownika wywołują ten wątek wykonania. Metody pomiędzy tą metodą a tym punktem (gdzie jest wyrzucany wyjątek) powinny po prostu informować, że żaden użytkownik nie istnieje (null, boolean, cokolwiek - to jest szczegóły implementacji).

Ale jeśli wszystkie procesy wewnątrz aplikacji wymagają użytkownika, i tak rzuciłbym wyjątek w tej metodzie...

 11
Author: Charles Bretana,
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
2009-11-28 11:43:59

Osobiście zwróciłbym null, ponieważ tak właśnie powinna działać warstwa DAL/repozytorium.

Jeśli nie istnieje, nie zwracaj niczego, co można by uznać za pomyślnie pobrane obiekt, null działa tutaj pięknie.

Najważniejszą rzeczą jest być konsekwentnym w całej warstwie DAL/Repos, dzięki czemu nie pomylisz się, jak go używać.

 10
Author: Alex Moore,
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
2009-10-26 18:47:51

I tend to

  • return null Jeśli ID obiektu nie istnieje, gdy nie wiadomo wcześniej, czy powinien istnieć.
  • throw Jeśli identyfikator obiektu nie istnieje, gdy powinien istnieć .

Rozróżniam te dwa scenariusze za pomocą tych trzech rodzajów metod. Pierwszy:

Boolean TryGetSomeObjectById(Int32 id, out SomeObject o)
{
    if (InternalIdExists(id))
    {
        o = InternalGetSomeObject(id);

        return true;
    }
    else
    {
        return false;
    }
}

Drugi:

SomeObject FindSomeObjectById(Int32 id)
{
    SomeObject o;

    return TryGetObjectById(id, out o) ? o : null;
}

Trzeci:

SomeObject GetSomeObjectById(Int32 id)
{
    SomeObject o;

    if (!TryGetObjectById(id, out o))
    {
        throw new SomeAppropriateException();
    }

    return o;
}
 7
Author: Johann Gerell,
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-19 12:04:44

Jeszcze inne podejście polega na przekazaniu obiektu zwrotnego lub delegata, który będzie operował na wartości. Jeśli wartość nie zostanie znaleziona, wywołanie zwrotne nie zostanie wywołane.

public void GetUserById(Guid id, UserCallback callback)
{
    // Lookup user
    if (userFound)
        callback(userEntity);  // or callback.Call(userEntity);
}

To działa dobrze, gdy chcesz uniknąć sprawdzania null w całym kodzie, a gdy nie znalezienie wartości nie jest błędem. Możesz również dostarczyć wywołanie zwrotne, gdy nie zostaną znalezione obiekty, jeśli potrzebujesz specjalnego przetwarzania.

public void GetUserById(Guid id, UserCallback callback, NotFoundCallback notFound)
{
    // Lookup user
    if (userFound)
        callback(userEntity);  // or callback.Call(userEntity);
    else
        notFound(); // or notFound.Call();
}

To samo podejście przy użyciu jednego obiektu może wyglądać następująco:

public void GetUserById(Guid id, UserCallback callback)
{
    // Lookup user
    if (userFound)
        callback.Found(userEntity);
    else
        callback.NotFound();
}

Od a perspektywa projektowania, bardzo podoba mi się to podejście, ale ma tę wadę, że strona połączeń jest bardziej obszerna w językach, które nie obsługują funkcji pierwszej klasy.

 6
Author: Marc,
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
2009-11-07 15:05:25

Używamy CSLA.NET i przyjmuje pogląd, że nieudane pobieranie danych powinno zwrócić "pusty" obiekt. W rzeczywistości jest to dość irytujące, ponieważ wymaga konwencji sprawdzania, czy obj.IsNew ratern niż obj == null.

Jak wspomniano wcześniej, zwracane wartości null spowodują natychmiastową awarię kodu, zmniejszając prawdopodobieństwo problemów z ukryciem spowodowanych przez puste obiekty.

Osobiście uważam, że jest bardziej elegancka.

To bardzo powszechna sprawa, a ja zaskoczony, że ludzie tutaj wydają się tym zaskoczeni: w każdej aplikacji internetowej dane są często pobierane za pomocą parametru querystring, który można oczywiście zniekształcić, więc wymagając, aby programista zajmował się przypadkami "not found".

Możesz sobie z tym poradzić przez:

if (User.Exists(id)) {
  this.User = User.Fetch(id);
} else {
  Response.Redirect("~/notfound.aspx");
}

...ale to za każdym razem dodatkowe połączenie do bazy danych, co może być problemem na stronach o dużym natężeniu ruchu. A także mając na uwadze, co następuje:

this.User = User.Fetch(id);

if (this.User == null) {
  Response.Redirect("~/notfound.aspx");
}

...wymaga tylko jednego połączenia.

 4
Author: Keith Williams,
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
2009-10-26 22:14:38

Wolę null, ponieważ jest kompatybilny z operatorem null-coalescing (??).

 4
Author: Andrew Medico,
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
2009-10-27 03:18:32

Powiedziałbym return null zamiast pustego obiektu.

Ale konkretny przypadek, o którym tu wspomniałeś, szukasz użytkownika według identyfikatora użytkownika, który jest Sortuj klucza do tego użytkownika, w takim przypadku prawdopodobnie chciałbym aby rzucić wyjątek, jeśli żadna instancja użytkownika nie jest znaleziono.

Jest to zasada, której generalnie przestrzegam:

  • Jeśli nie znaleziono wyniku operacji find by primary key, throw ObjectNotFoundException.
  • Jeśli nie znaleziono wyników znalezionych przez wszelkie inne kryteria, return null.
  • Jeśli nie znaleziono żadnego wyniku na znalezisku przez niekluczowe kryteria, które mogą zwracać wiele obiektów zwraca pustą kolekcję.
 4
Author: Partha Choudhury,
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-19 11:22:20

Będzie się różnić w zależności od kontekstu, ale generalnie zwrócę null, jeśli Szukam konkretnego obiektu (jak w twoim przykładzie) i zwrócę pustą kolekcję, jeśli Szukam zestawu obiektów, ale ich nie ma.

Jeśli popełniłeś błąd w kodzie i zwracanie null prowadzi do wyjątków wskaźnika null, to im szybciej to złapiesz, tym lepiej. Jeśli zwrócisz pusty obiekt, początkowe użycie go może zadziałać, ale później mogą pojawić się błędy.

 3
Author: Jacob Mattison,
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
2009-10-26 18:48:17

Najlepszy w tym przypadku zwraca "null" w przypadku, gdy nie ma takiego Użytkownika. Spraw, aby Twoja metoda była statyczna.

Edit:

Zazwyczaj metody tego typu są członkami jakiejś klasy "User" i nie mają dostępu do jej instancji. W tym przypadku metoda powinna być statyczna, w przeciwnym razie należy utworzyć instancję "User", a następnie wywołać metodę GetUserById, która zwróci kolejną instancję "User". Zgadzam się, że to jest mylące. Ale jeśli metoda GetUserById jest członkiem jakiejś " DatabaseFactory" klasa-nie ma problemu z pozostawieniem jej jako członka instancji.

 3
Author: Kamarey,
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
2009-10-26 19:14:43

Osobiście zwracam domyślną instancję obiektu. Powodem jest to, że oczekuję, że metoda zwróci zero do wielu lub zero do jednego(w zależności od celu metody). Jedynym powodem, dla którego byłby to stan błędu jakiegokolwiek rodzaju, przy użyciu tego podejścia, jest to, że metoda nie zwróciła żadnych obiektów i była zawsze oczekiwana(w kategoriach jednego do wielu lub pojedynczego zwrotu).

Co do założenia, że jest to kwestia domeny biznesowej - po prostu nie widzę tego z tej strony równanie. Normalizacja typów zwrotnych jest ważnym pytaniem o architekturę aplikacji. Co najmniej jest przedmiotem normalizacji w praktykach kodowania. Wątpię, czy istnieje użytkownik biznesowy, który powie "w scenariuszu X, po prostu daj im null".

 3
Author: Joseph Ferris,
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
2009-10-26 19:27:06

W naszych obiektach biznesowych mamy 2 główne metody Get:

Aby wszystko było proste w kontekście lub kwestionujesz, będą to:

// Returns null if user does not exist
public UserEntity GetUserById(Guid userId)
{
}

// Returns a New User if user does not exist
public UserEntity GetNewOrExistingUserById(Guid userId)
{
}

Pierwsza metoda jest używana podczas uzyskiwania konkretnych encji, druga metoda jest używana szczególnie podczas dodawania lub edycji encji na stronach internetowych.

To pozwala nam mieć to, co najlepsze z obu światów w kontekście, w którym są one używane.
 3
Author: Mark Redman,
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
2009-10-26 19:31:32

Jestem francuskim informatykiem, więc wybacz mój biedny angielski. W naszych klasach mówi się nam, że taka metoda nigdy nie powinna zwracać null, ani pustego obiektu. Użytkownik tej metody powinien najpierw sprawdzić, czy obiekt, którego szuka, istnieje, zanim spróbuje go zdobyć.

Używając Javy, jesteśmy proszeni o dodanie assert exists(object) : "You shouldn't try to access an object that doesn't exist"; na początku każdej metody, która może zwrócić null, aby wyrazić "warunek wstępny" (Nie wiem, co to jest słowo w języku angielskim).

IMO to naprawdę nie jest łatwe do używam, ale to jest to, czego używam, czekając na coś lepszego.
 3
Author: Saend,
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
2009-10-28 09:45:25

Jeśli przypadek, że użytkownik nie został znaleziony pojawia się wystarczająco często, i chcesz sobie z tym poradzić na różne sposoby w zależności od okoliczności (czasami rzucając wyjątek, czasami zastępując pustego użytkownika), Możesz również użyć czegoś podobnego do F#'S Option lub typu Haskell 's Maybe, który wyraźnie oddziela przypadek' no value 'od' found something!'. Kod dostępu do bazy danych może wyglądać następująco:

public Option<UserEntity> GetUserById(Guid userId)
{
 //Imagine some code here to access database.....

 //Check if data was returned and return a null if none found
 if (!DataExists)
    return Option<UserEntity>.Nothing; 
 else
    return Option.Just(existingUserEntity);
}

I być używane tak:

Option<UserEntity> result = GetUserById(...);
if (result.IsNothing()) {
    // deal with it
} else {
    UserEntity value = result.GetValue();
}

Niestety, każdy wydaje się żeby zrobić coś takiego na własną rękę.

 3
Author: yatima2975,
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
2009-10-28 10:58:54

Zazwyczaj zwracam null. Zapewnia szybki i łatwy mechanizm wykrywania, czy coś spieprzyło się bez rzucania wyjątków i używania ton try / catch w całym miejscu.

 2
Author: whatsisname,
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
2009-10-26 18:48:38

Dla typów kolekcji zwracam pustą kolekcję, dla wszystkich innych typów wolę używać wzorców NullObject do zwracania obiektu, który implementuje ten sam interfejs, co dla typu zwracającego. aby uzyskać więcej informacji na temat wzoru sprawdź link text

Używając wzorca NullObject będzie to:-

public UserEntity GetUserById(Guid userId)

{ // Wyobraź sobie jakiś kod tutaj, aby uzyskać dostęp do bazy danych.....

 //Check if data was returned and return a null if none found
 if (!DataExists)
    return new NullUserEntity(); //Should I be doing this here instead? return new UserEntity();  
 else
    return existingUserEntity;

}

class NullUserEntity: IUserEntity { public string getFirstName(){ return ""; } ...} 
 2
Author: vikram nayak,
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
2009-10-26 20:01:38

Ująć to, co inni powiedzieli w bardziej żałosny sposób...

wyjątki dotyczą wyjątkowych okoliczności

Jeśli ta metoda jest czystą warstwą dostępu do danych, powiedziałbym, że biorąc pod uwagę jakiś parametr, który zostanie zawarty w instrukcji select, można oczekiwać, że nie mogę znaleźć wierszy, z których można zbudować obiekt, a zatem zwracanie null byłoby dopuszczalne, ponieważ jest to logika dostępu do danych.

Z drugiej strony, jeśli oczekiwałem, że mój parametr będzie odzwierciedlał klucz podstawowy i powinienem dostać tylko Jeden wiersz z powrotem, jeśli mam więcej niż jeden z powrotem rzuciłbym wyjątek. 0 jest ok, aby zwrócić null, 2 nie jest.

Teraz, jeśli miałem jakiś kod logowania, który sprawdzał się przed dostawcą LDAP, a następnie sprawdzał przed DB, aby uzyskać więcej szczegółów i spodziewałem się, że będą one zsynchronizowane przez cały czas, mogę wyrzucić wyjątek wtedy. Jak mówili inni, takie są zasady biznesu.

Teraz powiem, że jest to ogólna zasada. Są momenty, w których możesz chcieć to złamać. Jednak moje doświadczenie i eksperymenty z C# (dużo tego) i Javą (trochę tego) nauczyły mnie, że radzenie sobie z wyjątkami jest znacznie droższe niż radzenie sobie z przewidywalnymi problemami za pomocą logiki warunkowej. Mówię do melodii 2 lub 3 rzędy wielkości droższe w niektórych przypadkach. Tak więc, jeśli to możliwe, że Twój kod może skończyć się w pętli, radzę zwrócić null i przetestować go.

 2
Author: Jim L,
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
2009-10-27 03:31:09

Wybacz mój pseudo-php/kod.

Myślę, że to naprawdę zależy od zamierzonego wykorzystania wyniku.

Jeśli chcesz edytować / modyfikować zwracaną wartość i zapisać ją, zwróć pusty obiekt. W ten sposób można użyć tej samej funkcji do wypełnienia danych na nowym lub istniejącym obiekcie.

Powiedzmy, że mam funkcję, która pobiera klucz główny i tablicę danych, wypełnia wiersz danymi, a następnie zapisuje wynikowy rekord do db. Ponieważ zamierzam wypełnić obiekt moimi danymi tak czy inaczej, uzyskanie pustego obiektu z gettera może być ogromną zaletą. W ten sposób mogę wykonywać identyczne operacje w obu przypadkach. Korzystasz z wyniku funkcji getter bez względu na wszystko.

Przykład:

function saveTheRow($prim_key, $data) {
    $row = getRowByPrimKey($prim_key);

    // Populate the data here

    $row->save();
}

Tutaj widzimy, że ta sama seria operacji manipuluje wszystkimi rekordami tego typu.

Jednakże, jeśli ostatecznym celem zwracanej wartości jest odczytanie i zrobienie czegoś z danymi, wtedy zwracałbym null. W ten sposób mogę bardzo szybko określ, czy dane nie zostały zwrócone i wyświetl odpowiedni komunikat dla użytkownika.

Zazwyczaj wyłapuję wyjątki w mojej funkcji, która pobiera dane (dzięki czemu mogę rejestrować komunikaty o błędach itp...) następnie zwróć null prosto z połowu. Generalnie nie ma znaczenia dla użytkownika końcowego, jaki jest problem, więc najlepiej jest zamknąć mój błąd rejestrowania / przetwarzania bezpośrednio w funkcji, która pobiera dane. Jeśli utrzymujesz współdzieloną bazę kodową w dowolnej dużej firmie, jest to szczególnie korzystne, ponieważ można wymusić odpowiednie rejestrowanie błędów/obsługę nawet najbardziej leniwego programisty.

Przykład:

function displayData($row_id) {
    // Logging of the error would happen in this function
    $row = getRow($row_id);
    if($row === null) {
        // Handle the error here
    }

    // Do stuff here with data
}

function getRow($row_id) {
 $row = null;
 try{
     if(!$db->connected()) {
   throw excpetion("Couldn't Connect");
  }

  $result = $db->query($some_query_using_row_id);

  if(count($result) == 0 ) {
   throw new exception("Couldn't find a record!");
  }

  $row = $db->nextRow();

 } catch (db_exception) {
  //Log db conn error, alert admin, etc...
  return null; // This way I know that null means an error occurred
 }
 return $row;
}
To moja ogólna zasada. Jak na razie działa dobrze.
 2
Author: ,
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
2009-10-28 03:12:45

Ciekawe pytanie i myślę, że nie ma "właściwej" odpowiedzi, ponieważ zawsze zależy to od odpowiedzialności Twojego kodu. Czy Twoja metoda wie, czy żadne znalezione dane nie stanowią problemu, czy nie? W większości przypadków odpowiedź brzmi " NIE " i dlatego zwrócenie null i umożliwienie obsługi rozmówcy jest idealne.

Może dobrym podejściem do odróżnienia metod rzucania od metod zwracających null jest znalezienie konwencji w swoim zespole: metody, które mówią, że "dostają" coś powinny rzucić wyjątek, jeśli nie ma nic do zdobycia. Metody, które mogą zwracać null, mogą być nazwane inaczej, być może " Find..."zamiast tego.

 2
Author: Marc Wittke,
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
2009-10-28 11:25:32

Jeśli zwracany obiekt jest czymś, co można iterować, zwracam pusty obiekt, więc nie muszę najpierw testować wartości null.

Przykład:

bool IsAdministrator(User user)
{
    var groupsOfUser = GetGroupsOfUser(user);

    // This foreach would cause a run time exception if groupsOfUser is null.
    foreach (var groupOfUser in groupsOfUser) 
    {
        if (groupOfUser.Name == "Administrators")
        {
            return true;
        }
    }

    return false;
}
 2
Author: Jan Aagaard,
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
2009-10-28 12:54:49

Lubię nie zwracać null z żadnej metody, ale zamiast tego używać opcji functional type. Metody, które nie mogą zwrócić żadnego wyniku zwracają pustą opcję, a nie null.

Również takie metody, które nie mogą zwrócić żadnego wyniku, powinny wskazywać, że poprzez ich nazwę. Zwykle umieszczam Try lub TryGet lub TryFind na początku nazwy metody, aby wskazać, że może ona zwrócić pusty wynik (np. TryFindCustomer, TryLoadFile, itp.).

, która pozwala rozmówcy stosować różne techniki, takie jak pipelining kolekcji (patrz Martin Fowler ' s Collection Pipeline) na wyniku.

Oto kolejny przykład, w którym zwracana opcja zamiast null jest używana do zmniejszenia złożoności kodu: Jak zmniejszyć złożoność Cyklomatyczną: Option Functional Type

 2
Author: Zoran Horvat,
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
2015-06-02 12:28:15

Więcej mięsa do zmielenia: powiedzmy, że mój DAL zwraca NULL dla GetPersonByID zgodnie z zaleceniami niektórych. Co powinien zrobić mój (raczej cienki) BLL, Jeśli otrzyma NULL? Przekaż tę wartość NULL i pozwól konsumentowi końcowemu martwić się o nią (w tym przypadku ASP.Net strona)? Co powiesz na to, żeby BLL rzucił wyjątek?

BLL może być używany przez ASP.Net i Win App, czy innej biblioteki klas - moim zdaniem niesprawiedliwe jest oczekiwanie, że konsument końcowy "wie", że metoda GetPersonByID zwraca null (chyba że są używane typy null).

Moim zdaniem (jeśli to coś warte) jest to, że mój DAL zwraca NULL, jeśli nic nie zostanie znalezione. Dla niektórych obiektów jest ok - może to być 0: wiele list rzeczy, więc nie posiadanie żadnych rzeczy jest w porządku (np. lista ulubionych książek). W tym przypadku mój BLL zwraca pustą listę. Dla większości rzeczy pojedynczego podmiotu (np. użytkownik, konto, faktura) jeśli nie mam takiego, to na pewno jest to problem i rzut kosztowny wyjątek. Jednak widząc, że użytkownik przez unikalny identyfikator, który został wcześniej podany przez aplikację, powinien zawsze zwracać użytkownika, wyjątek jest wyjątkiem "właściwym", ponieważ jest wyjątkowy. Konsument końcowy BLL (ASP.Net, f ' irinstance) tylko zawsze oczekuje, że rzeczy będą hunky-dory, więc nieobsługiwana Obsługa wyjątków będzie używana zamiast zawijania każdego pojedynczego wywołania GetPersonByID w bloku try-catch.

Jeśli jest rażący problem w moim podejściu, proszę dać mi znać, ponieważ zawsze chętnie się uczę. Jak inne plakaty mówiły, że wyjątki to kosztowne rzeczy, a podejście "sprawdzania najpierw" jest dobre, ale wyjątki powinny być właśnie takie-wyjątkowe.

Podoba mi się ten post, dużo dobrych propozycji scenariuszy "to zależy": -)

 1
Author: Mike Kingscott,
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
2009-10-28 11:11:16

Myślę, że funkcje nie powinny zwracać null, dla zdrowia twojej bazy kodu. Mogę wymyślić kilka powodów:

Będzie duża ilość klauzul ochronnych traktujących o null reference if (f() != null).

Czym jest null, czy jest to akceptowana odpowiedź czy problem? Czy null jest poprawnym stanem dla określonego obiektu? (wyobraź sobie, że jesteś klientem kodu). Chodzi mi o to, że wszystkie typy referencji mogą być null, ale czy powinny?

Posiadanie null w pobliżu prawie zawsze da kilka nieoczekiwanych Wyjątki NullRef od czasu do czasu, gdy baza kodu rośnie.

Istnieją pewne rozwiązania, tester-doer pattern lub implementacja option type z programowania funkcyjnego.

 1
Author: gavri,
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-17 10:00:25

Jestem zdumiony liczbą odpowiedzi (w całej sieci), które mówią, że potrzebujesz dwóch metod: metody "Isitthere()" i metody "GetItForMe ()" i tak prowadzi to do stanu rasy. Co jest złego w funkcji, która zwraca null, przypisując ją do zmiennej i sprawdzając zmienną dla Null w jednym teście? Mój poprzedni kod C był wypełniony

If (NULL != (zmienna = function (arguments...)) ) {

Więc otrzymujesz wartość (lub null) w zmiennej, a wynik na raz. Czy ten idiom został zapomniany? Dlaczego?

 0
Author: no comprende,
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
2014-11-07 16:06:15

Zgadzam się z większością postów tutaj, które mają tendencję do null.

Moje rozumowanie jest takie, że generowanie pustego obiektu o nieujemnych właściwościach może powodować błędy. Na przykład encja z właściwością int ID ma wartość początkową ID = 0, która jest całkowicie poprawną wartością. Gdyby ten obiekt, w pewnych okolicznościach, został zapisany do bazy danych, byłoby to złe.

Dla czegokolwiek z iteratorem, ja zawsze używam zbioru pustego. Coś jak

foreach (var eachValue in collection ?? new List<Type>(0))

To zapach kodu moim zdaniem. Właściwości kolekcji nie powinny być null, nigdy.

Przypadku krawędzi jest String. Wiele osób mówi, że {[5] }nie jest naprawdę konieczne, ale nie zawsze można odróżnić pusty łańcuch od null. Co więcej, niektóre systemy bazodanowe (Oracle) nie rozróżniają ich w ogóle ('' jest zapisywane jako DBNULL), więc jesteś zmuszony obsługiwać je jednakowo. Powodem tego jest to, że większość wartości ciągów pochodzi z wejścia użytkownika lub z zewnętrznego systemy, podczas gdy ani pola tekstowe, ani większość formatów exchange nie mają różnych reprezentacji dla '' i null. Więc nawet jeśli użytkownik chce usunąć wartość, nie może zrobić nic więcej niż wyczyszczenie kontrolki wejściowej. Również rozróżnienie pól bazy danych nullable i non-nullable nvarchar jest bardziej niż wątpliwe, jeśli twój DBMS nie jest oracle - obowiązkowe pole, które pozwala '' jest dziwne, Twój interfejs nigdy by na to nie pozwolił, więc Twoje ograniczenia nie mapują. Więc odpowiedź tutaj, moim zdaniem jest, traktuj je jednakowo, zawsze.

Dotyczące Twojego pytania dotyczącego wyjątków i wydajności: Jeśli rzucisz wyjątek, którego nie możesz całkowicie obsłużyć w swojej logice programu, musisz w pewnym momencie przerwać cokolwiek Twój program robi i poprosić Użytkownika o ponowne wykonanie tego, co właśnie zrobił. W takim przypadku kara za wydajność catch jest naprawdę najmniejszym z twoich zmartwień - poproszenie użytkownika to słoń w pokoju (co oznacza ponowne renderowanie całego interfejsu użytkownika lub wysłanie niektórych HTML przez internet). Więc jeśli nie zastosujesz się do anty-wzorca " Program Flow with Exceptions", nie kłopocz się, po prostu rzuć jeden, jeśli ma to sens. Nawet w skrajnych przypadkach, takich jak "wyjątek walidacji", wydajność naprawdę nie jest problemem, ponieważ musisz zapytać użytkownika ponownie, w każdym przypadku.

 0
Author: Oliver Schimmer,
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 12:26:23

An Asynchroniczny Wzór Trygetowy:

Dla metod synchronicznych, wierzę @ Johann Gerell ' s odpowiedź jest wzorem do użycia we wszystkich przypadkach.

Jednak wzorzec TryGet z parametrem out nie działa z metodami asynchronicznymi.

Z literałami krotki C # 7 możesz teraz to zrobić:

async Task<(bool success, SomeObject o)> TryGetSomeObjectByIdAsync(Int32 id)
{
    if (InternalIdExists(id))
    {
        o = await InternalGetSomeObjectAsync(id);

        return (true, o);
    }
    else
    {
        return (false, default(SomeObject));
    }
}
 0
Author: ttugates,
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-07-27 21:03:42