数学的な未知数を表すNullableクラスメンバ

私がクラス Point を持っているとしましょう:

class Point
{
    public double? x, y;
}

x または y のいずれかが不明であることを示すために、その型をnull可能にしました。

さて、これらの値を数式で使用するときは、毎回その値を2倍にキャストしなければならないという不都合があります。私。 Math.Sin(p.x)はコンパイル時エラーを生成します。代わりにそれをキャストする必要があります: Math.Sin((double)p.x)

キャストの問題を回避するための私のアプローチは、ラッパーがキャストを実行するプロパティのみを読み取るようにすることです。

class Point
{
    public double? x, y;

    public double X { get { if (x != null) return (double)x; else throw new Exception(); } }
    public double Y { get { if (y != null) return (double)y; else throw new Exception(); } }
}

これは良いアプローチですか?

2

2 答え

Nullable Value プロパティを使用できます。

Math.Sin(p.x.Value)

または

public double X { get { return x.Value; } }

値が設定されていない場合は例外をスローします。これはコードと同じです。

アプローチの相対的メリットについて:

IMO the property based approach shields consumers from the implementation detail that x is internally stored as a Nullable to represent unknown-ness. This would be my preference if consumers are only expected to deal with 'known' values. If however, consumers are expected to cater fまたはa situation where x remains 'unknown' then exposing a Nullable property would be the way to go (and any consumers can check using the HasValue property of Nullable).

5
追加された

I'm personally not a big fan of the generic exception that is thrown when trying to access to a property (in particular the generic InvalidOperationException thrown when accessing .Value of Nullable when HasValue == false). I would instead expose boolean properties that specify if the values are defined:

開発者がプロ​​パティへのアクセスを試みる前にメンバーの有効性をチェックするのは契約の一部です:

public class Point
{
    private double? x;
    private double? y;

    public bool IsXDefined { get { return this.x.HasValue; } }

    public bool IsYDefined { get { return this.y.HasValue; } }

   //Returns an undefined value (default(double)) in case X is not defined
   //This is a part of the contract that X is valid if, and only if IsXDefined is true.
    public double X { get { return x ?? default(double); } }

    public double Y { get { return y ?? default(double); } }
}

Point p = new ...
if (p.IsXDefined)
{
    double zz = p.X ....
}

実際には同じ目的のために異なるアプローチがありますが、重要なことは開発者がコードが実際に何をしているのかを認識していることです。例外として、開発者が読もうとしているプロパティが良好な状態ではないことを知ることができます。

X が有効な値であることを確認するには、 IsXDefined をチェックしてください。 code>このプロパティにアクセスする前にtrueを返します "。

PointCoordinateNotDefinedException も素晴らしいです:

public double X
{
    get
    {
        if (this.IsXDefined)
        {
            return this.x.Value;
        }

        throw new PointCoordinateNotDefinedException();
    }
}

座標が定義されていない場合、 IsXDefined をチェックすると、Xプロパティのドキュメンテーションで " PointCoordinateNotDefinedException /code>はこのプロパティへのアクセスを試みる前にtrueを返します "。

どちらも問題ありません。値が指定されていないとアプリケーションがクラッシュするため、アプリケーションが誤った値で実行されることがありません(スタックトレースを調べるよりもデバッグが難しい例外をスローする))。

しかし、例外をスローするまでプロパティにアクセスしようとしているとは思わない(例外をキャッチしている間)は良い考えです。プロパティにアクセスする前に、 IsXDefined ブール値をテストすることをお勧めします。

2
追加された
nullableに値がないときにスローされる InvalidOperationException のファンではありませんが、代わりにデフォルト値を返すと、クラスの不注意なユーザーのバグが隠されます。私はむしろ例外をスローし、 InvalidOperationException が十分ではない場合は、 PointCoordinateNotDefinedException などを作成します。私はあなたがそのようなアプローチを考えていると推測しているので、なぜあなたがデフォルト値アプローチを好むのか不思議です。
追加された 著者 phoog,
@ ken2kクライアントはtry-catchを使用するのではなく、 IsXDefined を呼び出す必要があります。定義されたクラスはスレッドセーフではないため、マルチスレッドのプログラムでは、例外がスローされないことは保証されません。 IsXDefined X を呼び出す間に値をnullに設定できます。デフォルト値のアプローチは、クライアントが 0.0 を有効な値にすることを持っている X を読む前に、 IsXDefined
追加された 著者 phoog,
ところで、私は最初のコメントを投稿したときに私はすでにあなたの答えをupvotedので、あなたの投票合計が増加しない場合、私はあなたの編集をかわしているとは思わない:)
追加された 著者 phoog,
あなたはpublic double X {get {return x.HasValue? x:新しいPointCoordinateNotDefinedException()をスローします。 }}
追加された 著者 Jordan,
@phoog更新された答えをご覧ください。
追加された 著者 ken2k,