0

新しい例外を作成することが正当化されるのはいつですか。.Net Frameworkに関して新しい例外タイプを作成することを設計上適切に決定する前に、満たす必要のある条件を含むある種のチェックリストはありますか?

たとえば、次のことを考慮してください。

メソッドのコンシューマーが完了するのに重要ではないが、いくつかの追加情報を提供する整数を返すメソッドを持つクラスがあります。クラスのユーザーがこのメソッドを呼び出す方法に依存しないメソッドでは、問題が発生する可能性のあるさまざまなことがあります。1つはネットワーク接続が失われる可能性があること、もう1つはメソッドが呼び出そうとしているWebサービスのAPIが変更されたことです。メソッドのコンシューマーには、例外からの回復を試みるためにこれらのケースを異なる方法で処理する機能がありません。これらの操作に2つの異なる例外がある場合、またはより一般的な例外がある場合(たとえば、CommunicationFailureException)特定の説明と内部例外でこれらの両方のケースをカバーしていますか?または、メソッドがWebサービスの呼び出しに失敗したときに最初にスローされた.Net例外をスローする必要がありますか?

この特定の例をカバーするだけではなく、新しい例外タイプを作成するための原則を知っていただければ幸いです。

4

6 に答える 6

2

例外について何か追加のことを言う場合、つまり既存の例外でカバーされていない場合は、新しい例外タイプを作成します。

アプリケーションに特定の不変条件があり、それらが無効であることを通知する必要がある場合は、カスタム例外タイプに適した場所である可能性があります。これにより、アプリケーションに固有の例外をキャッチできます。

于 2012-05-18T09:56:02.090 に答える
1

2つのケースでカスタム例外を作成することは理にかなっていると思います。

  1. 例外にさらに情報を追加する必要がある場合。

  2. 例外の呼び出し元がその特定の例外をキャッチし、別の方法で処理する必要がある可能性がある場合。

それ以外の場合は、標準の例外クラスを使用することをお勧めします。

于 2012-05-18T09:57:45.313 に答える
0

この記事はいくつかの非常に良い指針を与えます。

特に次のように述べているセクション:

クライアントコードに役立つ情報がない場合は、新しいカスタム例外を作成しないようにしてください。

于 2012-05-18T09:56:17.977 に答える
0

このページで小さなチェックリストを確認できます:http://docs.oracle.com/javase/tutorial/essential/exceptions/creating.html

このサイトはJava用ですが、概念は同じです。

于 2012-05-18T09:56:37.667 に答える
0

.Net Frameworkは、メソッドを呼び出すルーチンが、によってスローされた例外と、予期せず処理しなかった方法で呼び出されたメソッドによってFooスローされた例外を区別できる手段を提供しません。は手がかりを提供するかもしれませんが、インライン化などの最適化のため、完全に信頼できるわけではありません。FooFooFooStackTrace

したがって、Foo呼び出し元に何らかの意味があると思われる例外をスローする場合は、エスケープするそのタイプの例外が実際にその意味を持つようにする必要があります。.Net Frameworkは、この点でやや不十分であることに注意してください。たとえば、の定義は、列挙中にコレクションが変更された場合にスローされることになっていることをIEnumerator.MoveNext()示しInvalidOperationExceptionます(場合によっては、コードがコレクションのコピーを作成して列挙することを提案します)が、何が起こるかを明確にしませんfromから呼び出されたルーチンが、MoveNext()他の理由でそのような例外をスローした場合。

多くの場合、カスタム例外を使用することは、このような問題を回避するための良い方法です。他の目的でスローされないタイプのルーチンから例外をスローする場合、それをキャッチするコードは、例外がそれが意味すると考えるものを意味することを確信できます。

于 2012-05-19T18:56:57.273 に答える
0

Odedは良い点を示しました。

このトピックに追加できると思うのは、APIの抽象化です。すべての実装に共通のコントラクトを提供する例外ラッパーを作成する必要があります。私はそれがodedの応答でカバーされていることを知っていますが、私はそれが指摘できると思いました:

void Main()
{
    try
    {
        IUserRepository = //assume that IoC container provides specific implementation
    }
    catch (UserNotFoundException e)
    {
        Console.WriteLine(string.Format("User not found: {0}", e.Id));
    }
}


class User
{
    public int Id {get;set;}
}

class UserNotFoundException : Exception
{
    public int Id {get;private set;}

    public UserNotFoundException(int id, Exception innerException)
        :base(string.Format("User {0} could not be found", id), innerException)
    {
        Id = id;
    }
}

interface IUserRepository
{
    User GetUser(int id);
}

class XmlUserRepository : IUserRepository
{
    string _path;

    public XmlUserRepository(string path)
    {
        _path = path;
    }

    public User GetUser(int id)
    {
        try
        {
            //retrieving code that might throw IOException or XmlException
        }
        catch (Exception e)
        {
            //catching Exception is not a good thing to do, but for the sake of clarity I made this like that
            throw new UserNotFoundException(id, e);
        }
    }
}

class DbUserRepository : IUserRepository
{
    string _dbConnectionString;

    public DbUserRepository(string dbConnectionString)
    {
        _dbConnectionString = dbConnectionString;
    }

    public User GetUser(int id)
    {
        try
        {
            //retrieving code that might throw SqlException
        }
        catch (Exception e)
        {
            //catching Exception is not a good thing to do, but for the sake of clarity I made this like that
            throw new UserNotFoundException(id, e);
        }
    }
}
于 2012-05-22T06:12:25.333 に答える