0

クラス プロパティを構造体であるかのように動作させたい場合がよくあります。(編集:実際には、構造体の仕組みを誤解していました。プロパティを構造体とまったく同じように動作させたくありません。操作とコピーの場合に異なる動作をさせたいのです。)

これが可能かどうか疑問に思っています。可能であれば、それは良い考えでしょうか。

2 つの単純なクラスがあるとします。

public class Cube
{
    public Point Center {get ; set;}
    ... // some more cube properties
}

public class Point 
{
    public virtual Double X {get {return this.x;} set{this.x = value;}}
    public virtual Double Y {...}
    public virtual Double Z {...}
    ...
}

今、私は次のように Cube.Center にアクセスしたいと思います:

Cube cube = new Cube();
cube.Center.X += 10.0; // cube1 should move 10.0 in X direction

Point point = cube.Center;
point.X += 10.0 // cube1 should NOT move here

Cube cube2 = new Cube();
cube2.Center = point;
cube2.Center.Y += 5.0; // cube2 should move, but cube1 should stay in place. 

私が理解している限り、クラスではなく構造体である Point の場合、値によって渡され、上記が期待される動作になります。(編集:構造体の仕組みを誤解していました。構造体ではそのようなcube.Center.X += 10.0ことはできません)

でも:

  • 可変構造体は悪です
  • オブジェクトには、この小さな例よりも多くのフィールドが含まれる場合があります。Microsoft では、メモリ フットプリントが非常に小さい構造体のみを推奨しています。
  • 最も重要なのは、構造体はクラスから継承できないため、このようなことは構造体では不可能です: キューブ センターの Point のプライベートな子クラスを持つことで、変更されるたびに追加の処理が行われます。

    public class Cube
    {
    
       // private child of Point, can only be used by Cube
       private class cubeCenter: Point
       {
           private Cube cube; // The cube this point belongs to
    
           public override double X 
           {
               get {return base.X} 
    
               // custom setter: whenever X changes, 
               // recalculate the bounding box of the cube
               set {base.X=value; cube.recalculateBoundingBox();} 
           }
           ... // + other overrides & constructor
       }
    
       private cubeCenter _center; 
    
       public Point Center 
       {
           get {return this._center} 
           set {this._center = new cubeCenter(value, this);}
       }
    
       ...
    }
    
    
    
    cube1.Center.X += 10.0; // now cube1 moves AND its bounding box is recalculated.
    

したがって、私が求めている動作は次のとおりです。 - のようなサブプロパティを変更できるはずcube1.Center.Xです。- これが発生するたびに、自分のカスタムcubeCenterセッターを実行したい。- ただし、誰かが Center: 全体をつかむPoint p = cube1.Centerと、割り当てられたオブジェクトはPointキューブに接続されていない通常のオブジェクトになります。

おそらく暗黙の変換演算子を使用して、これは可能ですか?

これは悪いデザインの選択ですか?他の提案をお待ちしています。

(私が検討したことの 1 つは、これらすべての問題を回避するために Points を不変にすることです。ただし、この場合、中心を変更するための見苦しくない構文を見つけることができません:)

    // this is the immutable equivalent to cube1.Center.X += 10.0
    cube1.Center = cube1.Center.WithX ( cube1.Center.X + 10.0 )
4

4 に答える 4

2

私は不変を好むでしょうstruct Point。移動は簡単です:

public static Point operator +(Point a, Point b) 
{
   return new Point(a.X + b.X, a.Y + b.Y, a.Z + b.Z);
}
⋮
cube1.Center = cube1.Center + new Point(10, 0, 0);

他のすべては非常にうまく収まるはずです。

于 2012-08-12T08:28:24.563 に答える
1

clone メソッドを作成して、コピーを明示的にすることができます。これは良いことです。読みやすくするために、コピーしているかどうかを明確に区別する必要があります。そうしないと、コードのデバッグが悪夢になる可能性があります。

public class Point
{
    public virtual Double X {get {return this.x;} set{this.x = value;}}
    public virtual Double Y {...}
    public virtual Double Z {...}

    public Point Clone() {
       return this.MemberwiseClone();
    }
}


Point point = cube.Center.Clone();
point.X += 10.0 // cube1 will NOT move here

MemberwiseCloneオブジェクトの浅いコピーを作成するため、ネストされた参照型を自分で複製する必要があります。

public class Cube
{
   public Point Center {get ; set;}

   public Cube Clone() {
       var cube = this.MemberwiseClone();
       cube.Center = this.Center.Clone();
       return cube;
   }

}

于 2012-08-12T08:45:12.503 に答える
0

プロパティのゲッターは、値が操作またはコピーに使用されるかどうかを認識できないため、必要なものを正確に取得することは不可能です。

ポイントをカプセル化し、それを複製するためのメソッドと操作するためのプロパティを提供できます。

public class Cube {
  private Point _center;
  public Point CopyCenter() { return _center.Clone(); }
  public double CenterX { get { return _center.X; } set { _center.X = value; } }
  public double CenterY { get { return _center.Y; } set { _center.Y = value; } }
  public double CenterZ { get { return _center.Z; } set { _center.Z = value; } }
}

使用法の構文はまったく同じではありませんが、少なくとも何が起こっているかは明らかです。

于 2012-08-12T08:49:38.950 に答える
0

Point実際の値のセマンティクスを作成するには、決して渡されない単一のインスタンスを保持し、それを置き換えないでください (クローン機能を に追加する必要がありますPoint)。

public class Cube {
    private readonly Point center = new Point();

    public Point Center {
        get {
            return center.Clone();
        }
        set {
            center.X = value.X;
            center.Y = value.Y;
        }
    }
    ... // some more cube properties
}

これらのセマンティクスにより、cube.Center.X = ...コードを使用できないことに注意してください。ただし、これは構造体にも当てはまります。

于 2012-08-12T08:26:06.437 に答える