Jak używać słowa kluczowego rzucającego w stylu Java w C #?

91

W Javie throwssłowo kluczowe pozwala metodzie zadeklarować, że sama nie obsłuży wyjątku, ale raczej wyrzuci go do metody wywołującej.

Czy istnieje podobne słowo kluczowe / atrybut w C #?

Jeśli nie ma odpowiednika, w jaki sposób możesz osiągnąć ten sam (lub podobny) efekt?

Louis Rhys
źródło

Odpowiedzi:

78

W Javie musisz albo obsłużyć wyjątek, albo oznaczyć metodę jako taką, która może ją zgłosić za pomocą throwssłowa kluczowego.

C # nie ma tego słowa kluczowego ani jego odpowiednika, tak jak w C #, jeśli nie obsłużysz wyjątku, będzie się pojawiał, dopóki nie zostanie złapany lub jeśli nie zostanie przechwycony, zakończy program.

Jeśli chcesz sobie z tym poradzić, rzuć ponownie, możesz wykonać następujące czynności:

try
{
  // code that throws an exception
}
catch(ArgumentNullException ex)
{
  // code that handles the exception
  throw;
}
Oded
źródło
1
„to się pojawi”, czy to oznacza, że ​​jest to równoważne wszystkim metodom mającym klauzulę throws w Javie?
Louis Rhys,
1
@Louis RH - coś w rodzaju. Oznacza to, że wyjątek, jeśli nie zostanie obsłużony, przejdzie w górę łańcucha wywołań przez każdą funkcję wywołującą, aż zostanie obsłużony.
Oded
1
@Louis RH nie do końca, co oznaczałoby, że musisz złapać wyjątek przynajmniej w swoim Main, aby skompilować kod. Ponieważ C # nie zna sprawdzonych wyjątków, to od Ciebie zależy, czy je złapiesz, w przeciwnym razie po prostu wylądują w środowisku wykonawczym i zakłócą Twój kod.
Johannes Wachter
1
@jwatcher: główna metoda może mieć również klauzulę throw.
Louis Rhys,
4
@AshishKamble - eh. Kwestia opinii. Obsługa wyjątków jest inna w .NET. Nie zakładaj, że wiesz, co jest „lepsze”.
Oded
108

Op pyta o C # odpowiednik throwsklauzuli Java - nie o throwsłowo kluczowe. Jest to używane w sygnaturach metod w Javie, aby wskazać, że może zostać zgłoszony sprawdzony wyjątek.

W języku C # nie ma bezpośredniego odpowiednika wyjątku sprawdzanego w Javie. C # nie ma równoważnej klauzuli podpisu metody.

// Java - need to have throws clause if IOException not handled
public void readFile() throws java.io.IOException {
  ...not explicitly handling java.io.IOException...
}

przetłumaczyć na

// C# - no equivalent of throws clause exceptions are unchecked
public void ReadFile() 
{
  ...not explicitly handling System.IO.IOException...
}
serg10
źródło
30

Tak, to stary wątek, jednak często znajduję stare wątki, gdy szukam odpowiedzi w Google, więc pomyślałem, że dodam coś przydatnego, co znalazłem.

Jeśli korzystasz z programu Visual Studio 2012, istnieje wbudowane narzędzie, którego można użyć, aby zezwolić na ekwiwalent „rzutów” na poziomie środowiska IDE.

Jeśli używasz komentarzy dokumentacji XML , jak wspomniano powyżej, możesz użyć tagu <exception>, aby określić typ wyjątku zgłaszanego przez metodę lub klasę, a także informacje o tym, kiedy lub dlaczego jest on generowany.

przykład:

    /// <summary>This method throws an exception.</summary>
    /// <param name="myPath">A path to a directory that will be zipped.</param>
    /// <exception cref="IOException">This exception is thrown if the archive already exists</exception>
    public void FooThrowsAnException (string myPath)
    {
        // This will throw an IO exception
        ZipFile.CreateFromDirectory(myPath);
    }
mvanella
źródło
4
OP, to jest twoja odpowiedź. Zgaduję, ale JAVA throwsprawdopodobnie nic nie znaczy dla środowiska wykonawczego, poza informacją dla programisty. Podobnie @mvanella wskazał tutaj, że C # robi dokładnie to samo. Zakładam, że już wiesz, że ta „dokumentacja xml” ma ważniejszy cel. Wiem, że ten wątek jest stary.
Hari Lubovac
W rzeczywistości Java nie wyświetla wyjątków, chyba że jest to wyraźnie określone w throwsklauzuli lub wyrzucone przez throwpolecenie. Oznacza to, że jeśli wystąpi wyjątek RunTimeException i nie jest obsługiwany w tej samej metodzie, w której występuje, wykonanie zostanie zatrzymane w tym miejscu.
Pedro Lima
18

Oto odpowiedź na podobne pytanie, które właśnie znalazłem na bytes.com :

Krótka odpowiedź brzmi: nie. Nie ma żadnych sprawdzonych wyjątków w C #. Projektant języka omawia tę decyzję w tym wywiadzie:

http://www.artima.com/intv/handcuffs.html

Najbliższym, co możesz uzyskać, jest użycie tagów w dokumentacji XML i rozpowszechnianie wygenerowanych przez NDoc dokumentów z kodem / zestawami, aby inne osoby mogły zobaczyć, które wyjątki rzucasz (co jest dokładnie tym, co robi MS w dokumentacji MSDN). Nie możesz jednak polegać na kompilatorze, który poinformuje Cię o nieobsłużonych wyjątkach, tak jak możesz być przyzwyczajony w Javie.

Andreas Dolk
źródło
7

Po przejrzeniu większości odpowiedzi tutaj, chciałbym dodać kilka myśli.

  1. Poleganie na komentarzach do dokumentacji XML i oczekiwanie, że inni będą na nich polegać, to kiepski wybór. Większość kodu C #, z którym się spotkałem, nie dokumentuje metod całkowicie i spójnie z komentarzami dokumentacji XML. A potem jest większy problem, w jaki sposób bez sprawdzonych wyjątków w C # można udokumentować wszystkie wyjątki, które metoda generuje, aby użytkownik interfejsu API wiedział, jak obsługiwać je wszystkie indywidualnie? Pamiętaj, że wiesz tylko o tych, które rzucasz sobie za pomocą słowa kluczowego throw w swojej implementacji. Interfejsy API, których używasz w implementacji metody, mogą również generować wyjątki, o których nie wiesz, ponieważ mogą nie być udokumentowane i nie obsługujesz ich w swojej implementacji, więc wybuchną w obliczu wywołującego metoda. Innymi słowy,

  2. Andreas połączył wywiad z Andersem Hejlsbergiem w odpowiedziach tutaj na temat tego, dlaczego zespół projektowy C # zdecydował się na sprawdzone wyjątki. Ostateczna odpowiedź na pierwotne pytanie jest ukryta w tym wywiadzie:

Programiści chronią swój kod, pisząc ostatecznie wszędzie try, więc wycofają się poprawnie, jeśli wystąpi wyjątek, ale tak naprawdę nie są zainteresowani obsługą wyjątków.

Innymi słowy, nikogo nie powinno interesować, jakiego rodzaju wyjątków można się spodziewać w przypadku konkretnego interfejsu API, ponieważ zawsze będziesz je łapać wszędzie. A jeśli naprawdę chcesz obchodzić się z określonymi wyjątkami, to jak sobie z nimi poradzić, zależy od ciebie, a nie od kogoś, kto definiuje sygnaturę metody za pomocą czegoś takiego jak słowo kluczowe Java throws, wymuszając określoną obsługę wyjątków u użytkownika API.

-

Osobiście jestem tu rozdarty. Zgadzam się z Andersem, że zaznaczenie wyjątków nie rozwiązuje problemu bez dodania nowych, innych problemów. Podobnie jak w przypadku komentarzy do dokumentacji XML, rzadko widzę kod C # zawierający wszystko, co jest opakowane w bloki try last. Wydaje mi się, że to rzeczywiście jedyna opcja i coś, co wydaje się dobrą praktyką.

Tobias
źródło
3

Faktycznie brak sprawdzania wyjątków w C # można uznać za dobrą lub złą rzecz.

Osobiście uważam to za dobre rozwiązanie, ponieważ sprawdzone wyjątki powodują następujące problemy:

  1. Wyjątki techniczne przeciekają do warstwy biznesowej / domeny, ponieważ nie można ich poprawnie obsłużyć na niskim poziomie.
  2. Należą do sygnatury metody, która nie zawsze dobrze współgra z projektowaniem API.

Z tego powodu w większości większych aplikacji często zobaczysz następujący wzorzec po zaznaczeniu Wyjątki:

try {
    // Some Code
} catch(SomeException ex){
    throw new RuntimeException(ex);
}

Co zasadniczo oznacza emulowanie sposobu, w jaki C # / .NET obsługuje wszystkie wyjątki.

Johannes Wachter
źródło
Nie mogę sobie wyobrazić, jak sprawdzone wyjątki zmieszałyby się z lambdami!
Gabe
@ Gabe: Jestem pewien, że mógłbyś wymyślić jakąś koncepcję, która pozwoli ci je mieszać, ale tak jak powiedziałem, sprawdzone wyjątki są w Javie również przeważnie nie są dobrą praktyką, szczególnie w bardziej złożonych aplikacjach. Więc dobrze, że nie ma ich w C #.
Johannes Wachter
3

Pytasz o to:

Ponowne zgłoszenie wyjątku

public void Method()
{
  try
  {
      int x = 0;
      int sum = 100/x;
  }
  catch(DivideByZeroException e)
  {
      throw;
  }
}

lub

static void Main() 
    {
        string s = null;

        if (s == null) 
        {
            throw new ArgumentNullException();
        }

        Console.Write("The string s is null"); // not executed
    }
Pranay Rana
źródło
3
+1 za używanie throw. Używając go, ślad stosu nie zostanie utracony.
Giuseppe Accaputo,
2

Istnieją pewne przelotne podobieństwa między .Net CodeContract EnsuresOnThrow<>a throwsdeskryptorem java , ponieważ oba mogą sygnalizować wywołującemu jako typ wyjątku, który może zostać wywołany z funkcji lub metody, chociaż istnieją również duże różnice między 2:

  • EnsuresOnThrow<>wykracza poza zwykłe określenie, które wyjątki mogą zostać rzucone, ale także określa warunki, w których są one gwarantowane - może to być dość uciążliwy kod w wywołanej metodzie, jeśli warunek wyjątku nie jest łatwy do zidentyfikowania. Java throwszapewnia wskazanie, które wyjątki mogą zostać wyrzucone (tj. IMO fokus w .Net znajduje się wewnątrz metody, która kontraktuje, aby udowodnić throw, podczas gdy w Javie fokus przenosi się do wywołującego, aby potwierdzić możliwość wystąpienia wyjątku).
  • .Net CC nie rozróżnia wyjątków zaznaczonych i niezaznaczonych, które ma Java, chociaż sekcja 2.2.2 podręcznika CC wspomina o

„używaj wyjątkowych warunków końcowych tylko dla tych wyjątków, których wywołujący powinien oczekiwać w ramach interfejsu API”

  • W .Net dzwoniący może określić, czy ma robić cokolwiek z wyjątkiem (np. Wyłączając umowy). W Javie wywołujący musi coś zrobić , nawet jeśli doda throwsdla tego samego wyjątku w swoim interfejsie.

Kod kontraktów instrukcja tutaj

StuartLC
źródło
0

Jeśli celem metody C # jest tylko zgłoszenie wyjątku (jak mówi typ powrotu js), polecam po prostu zwrócić ten wyjątek. Zobacz przykład poniżej:

    public EntityNotFoundException GetEntityNotFoundException(Type entityType, object id)
    {
        return new EntityNotFoundException($"The object '{entityType.Name}' with given id '{id}' not found.");
    }

    public TEntity GetEntity<TEntity>(string id)
    {
        var entity = session.Get<TEntity>(id);
        if (entity == null)
            throw GetEntityNotFoundException(typeof(TEntity), id);
        return entity;
    }

PRZYZNAĆ
źródło
-1

Dla tych, którzy się zastanawiają, nie musisz nawet definiować tego, co złapiesz, aby przekazać to do następnej metody. Jeśli chcesz, aby cała obsługa błędów była w jednym głównym wątku, możesz po prostu złapać wszystko i przekazać dalej w ten sposób:

try {
    //your code here
}
catch {
    //this will throw any exceptions caught by this try/catch
    throw;
}
Simon Jensen
źródło
Proszę dokonać edycji odpowiedzi. Przypadkowo kliknąłem -1. Nie mogę go usunąć, dopóki nie wprowadzisz żadnych zmian.
proximab