プロパティから例外をスローするのは悪い形ですか?


14

私は常に、プロパティ(つまり、設定/取得操作)が高速/即時であり、障害が発生しないことを念頭に置いてきました。プロパティを取得または設定することを試みる/キャッチする必要はありません。

しかし、いくつかのオブジェクトのプロパティにロールベースのセキュリティを適用するいくつかの方法を検討しています。たとえば、Employee.Salaryプロパティ。他の人が試したいくつかのソリューション(特に1つはここのAOPの例です)は、アクセサに適切な権限がない場合に例外をスローすることを伴います-しかし、これは私が持っていた個人的なルールに反します今長い間。

だから私は尋ねる:私は間違っていますか?状況は変わりましたか?プロパティが例外をスローできることは受け入れられていますか?


1
StackOverflowでのこれと同じ質問が注目を集め、より良い回答を得ました。
ローマンスターコフ

回答:


14

プロパティの値を設定するときに、無効な値に対して例外をスローしても問題ありません

プロパティの値を取得しても、(ほとんど)例外がスローされることはありません

役割ベースのアクセスの場合は、異なる/暗いインターフェイスまたはファサードを使用します。持っていないものを人々に見せないでください!


5

私はそれがほとんど悪い形であると考えます、しかし、Microsoftでさえ時々例外を使うことを勧めます。良い例は、抽象プロパティStream.Lengthです。ガイドラインが進むにつれて、ゲッターでの副作用の回避とセッターでの副作用の制限に関心を持つようになります。


4

プロパティセッターまたはゲッターから例外をスローする必要があると感じた場合、設計に欠陥があると私は間違いなく主張します。

プロパティは、単なる値である何かを表す抽象化です。また、例外をスローすることを恐れずに値を設定できるはずです。*

プロパティを設定すると副作用が発生する場合は、代わりにメソッドとして実際に実装する必要があります。また、副作用が発生しない場合、例外はスローされません。

別の回答ですでに言及されている1つの例は、Stream.Positionプロパティです。これにより副作用が発生し、例外がスローされる場合があります。しかし、このプロパティセッターは基本的に、Stream.Seek代わりに呼び出すことができるラッパーです。

個人的に、私はそのポジションが書き込み可能な財産であるべきではないと考えています。

プロパティセッターから例外をスローしたくなる別の例は、データの検証です。

public class User {
    public string Email {
        get { return _email; }
        set { 
            if (!IsValidEmail(value)) throw InvalidEmailException(value);
            _email = value;
        }
    }

しかし、この問題に対するより良い解決策があります。有効なメールアドレスを表すタイプを導入します:

public class Email {
    public Email(string value) {
        if (!IsValidEmail(value)) throw new InvalidEmailException(value);
        ...
    }
    ...
}

public class User {
    public Email Email { get; set; }
}

このEmailクラスは、有効なメールアドレスではない値を保持できないようにし、メールを保存する必要があるクラスは、それらを検証する義務から解放されます。

これはまた、より高い結束性(優れたソフトウェア設計の指標)につながります。電子メールアドレスとその検証方法に関する知識は、Emailその懸念のみを有するクラスにのみ存在します。

* ObjectDisposedExceptionは、現時点で考えられる唯一の有効な例外です(しゃれはありません)。


2

あなたの質問は.NET固有のものであることは知っていますが、C#はJavaといくつかの歴史を共有しているので、興味があるかもしれません。私はない何かがJavaで行われるため、それはC#で行われるべきであることを意味している任意の方法で。特に、C#でプロパティに対する言語レベルのサポートが大幅に改善されている点で、この2つが非常に異なることを知っています。コンテキストと視点を与えているだけです。

JavaBeans仕様から:

制約されたプロパティプロパティの変更が発生したときに、他のBeanが変更を検証し、不適切な場合は拒否する場合があります。この種のチェックを受けるプロパティを制約付きプロパティと呼びます。Java Beansでは、PropertyVetoExceptionをサポートするために、制約付きプロパティセッターメソッドが必要です。これは、更新の試行が拒否される可能性があることを制約されたプロパティのユーザーに文書化します。したがって、単純な制約付きプロパティは次のようになります。

PropertyType getFoo();
void setFoo(PropertyType value) throws PropertyVetoException;

塩一粒でこれらすべてをしてください。JavaBeans仕様は古く、C#プロパティ(IMO)は、Javaが持つ「命名規則」ベースのプロパティを大幅に改善しています。私はちょっとした文脈を与えようとしているだけです!


それは良い点ですが、セッターメソッドとac#プロパティセッターの違いは、私にとって異なるケースになるほど十分に重要です。同様に、Javaのチェックされた例外は、例外がスローされる可能性があることを呼び出し元のコードに強制するため、これが誰かを驚かせる可能性が低くなります。
スティーブンエバーズ

2

プロパティのポイントはUniform Access Principleです。つまり、ストレージまたは計算によって実装されるかどうかにかかわらず、値は同じインターフェースを介してアクセス可能でなければなりません。プロパティがプログラマーの制御を超えたエラー状態を表す例外をスローしている場合、その例外はキャッチされて処理されるはずの種類であり、計算によって値が取得されたことをクライアントに強制します。

一方、キャッチされたり処理されたりするのではなく、APIの不正な使用をプログラマーに知らせることを目的とするアサーションまたはアサーションのような例外を使用しても問題はありません。これらの場合、APIユーザーの観点からの正解は、例外を処理することではありません(したがって、値が計算またはストレージのどちらで取得されるかを暗黙的に気にします)。オブジェクトが無効な状態にならないようにコードを修正するか、アサーションが起動しないようにコードを修正します。


「計算によって値が取得されたことをクライアントに強制する」方法はわかりません。確かにストレージへのアクセスも例外をスローする可能性があります。実際、この2つの違いをどのように定義しますか?
ティムウィ

区別されるのは、フィールド(ストレージ)から値を取得し、適切な型の変数に配置する(キャストを行わないなど)無害な操作を行うだけでは、例外をスローできないということです。その場合、値を使用して何かを行った場合にのみ例外が発生します。プロパティゲッターで例外がスローされている場合、その場合、値を取得して変数に配置するだけで例外が発生する可能性があります。
ワイリー博士の見習い

1

知る限り、このガイダンスは主に、プロパティが設計時に使用される可能性があるという思考プロセスに基づいています。(たとえば、TextBoxのTextプロパティ)デザイナーがアクセスしようとしたときにプロパティが例外を投げた場合、VSは良い一日を過ごすことができません。デザイナーを使用しようとするとエラーが発生し、UIデザイナーの場合はレンダリングされません。デバッグ時にも適用されますが、例外シナリオで表示されるのは「xxx例外」だけであり、VS IIRCを上書きすることはありません。

POCOにとっては、実際には何の害もありませんが、私はまだ自分でやるのをためらっています。人々はプロパティにもっと頻繁にアクセスしたいと思うので、通常は低コストであるはずです。プロパティはメソッドの動作を行うべきではなく、単に情報を取得/設定し、一般的なルールとしてそれを行う必要があります。


0

多くはコンテキストに依存しますが、一般的に、プロパティに例外を含むあらゆる種類の壊れやすいロジックを配置することは避けます。一例として、リフレクションを使用してプロパティを反復処理し、設計時に予期していなかったエラーが発生する可能性のあることがたくさんあります。

絶対に、間違いなく、結果をあまり心配せずに何かをブロックしたいときがあるかもしれないので、私は一般的に言います。セキュリティは、そこでの典型的なケースだと思います。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.