-2

昨日、C#コードで奇妙な動作を検出しました。私のセットアップは(正確ではありませんが、比較可能です)次のとおりです。

ユーザーにはチェックボックスのグリッドが表示されます。ここで、チェックボックスを中央の座標0,0に割り当てます。

2つの座標を簡単に比較できるように構造体を作成しました。

public struct Coord
{
  public int x, y;

  public static bool operator == (Coord coord1, Coord coord2)
  {
    return coord1.x == coord2.x && coord1.y == coord2.y;
  }

  public static bool operator != (Coord coord1, Coord coord2)
  {
    return coord1.x != coord2.x || coord1.y != coord2.y;
  }

  public override int GetHashCode()
  {
    return this.x.GetHashCode() ^ this.y.GetHashCode();
  }

  public override bool  Equals(object obj)
  {
    if (!(obj is Coord))
      return false;

    Coord coord = (Coord)obj;

    if (coord.x == this.x && coord.y == this.y)
      return true;
    return false;
  }
}

チェックボックスには、標準のWinFormsチェックボックスから継承するPositionというクラスを使用します。

public class Position : CheckBox
{
  public Coord coord;
  public List<Position> nearPositions = new List<Position>();

  public Position(int x, int y)
  {
    this.coord.x = x;
    this.coord.y = y;
  }

  protected override void OnClick(EventArgs e)
  {
    if (this.Checked)
      return;

    base.OnClick(e);

    this.checkConnections();
  }

  private void checkConnections()
  {
    foreach (Position position in this.nearPositions)
    {
      Route route = new Route(this, position);
    }
  }
}

ご覧のとおり、ユーザーは各チェックボックスを1回だけクリックできます。
List nearPositionsには、この近くのクリックされたチェックボックスのみが含まれています
ここで、checkConnections()メソッドで、クリックされたすべての(または一部の)チェックボックスを円に接続できるかどうかを調べます。したがって、可能なパスごとに、クラスRouteの新しいオブジェクトを作成します。

public class Route
{
  private Position startPosition;
  private List<Position> nodes = new List<Position>();

  public Route(Position startPosition, Position nextPosition)
  {
    this.startPosition = startPosition;
    this.nodes.Add(nextPosition);
    this.findConnection();
  }

  public Route(Route route, Position nextPosition)
  {
    this.startPosition = route.startPosition;
    this.nodes = route.nodes;
    this.Add(nextPosition);
    this.findConnection();
  }

  private void findConnection()
  {
    if (this.nodes.Count > 2 && this.nodes[this.nodes.Count - 1].nearPositions.Contains(this.startPosition))
    {
      //HERE THE ROUTE IS A CIRCLE
      return;
    }
    List<Position> nextPositions = this.nodes[this.nodes.Count - 1].nearPositions.FindAll(p => !p.Equals(this.startPosition) && !this.nodes.Contains(p));
    foreach (Position position in nextPositions)
    {
      if (this.nodes[this.nodes.Count - 1].nearPositions.FindAll(p => !p.Equals(this.startPosition) && !this.nodes.Contains(p)).Contains(position)) //TODO strange problem here...bad workaround need to fix
      {
        Route route = new Route(this, position);
      }
    }
  }
}

可能性ごとにRouteのオブジェクトを作成することを忘れないでください。したがって、円に多くのチェックボックスが含まれている場合、同時に多くのルートオブジェクトが存在します。たぶん、私の問題を再現することが重要です。
ルートのstartPositionは常に同じです。そのユーザーがクリックした位置。
リストノードに、クリクルを作成するための手順を保存します。

これで、findConnection()メソッドの内部が取得されます。リストnextPositionには、this.nodes[this.nodes.Count-1].nearPositionsリスト内にも存在しないPositionsが含まれる場合があります。そのため、foreachループ内に追加の条件を追加しました。

.FindAll()メソッドのバグか、同時に複数のeoutesの終了に関する問題である可能性があるという私の考え。

だから私の質問:
1。私の問題を再現できますか?
2.それはどこから来たのですか?
3.どうすれば解決できますか?

返信ありがとうございます!

4

2 に答える 2

1

問題を特定し、機能していないことを示す短いコードを投稿するようにしてください。すべての詳細を読み、アルゴリズムを理解するのはやや時間がかかり、ほとんどの詳細は関係ありません。

そうは言っても、私が見た疑わしいことの1つは、Coord構造体の定義方法にありました。メンバーを正しく比較する等式演算子オーバーライドを指定しましたが、Equalsオーバーライドではメンバーを比較しません。

問題がFindAll正しく機能しておらず、デバッガーを使用してリストの内容が正しいことを確認した場合は、このEqualオーバーライドが問題の原因である可能性があります。

GetHashCodeまた、メンバーの値を組み合わせるようにオーバーライドを変更する必要があります。

于 2012-11-14T21:46:25.583 に答える
0

私は解決策を見つけました。
問題はにあります

public Route(Route route, Position nextPosition)
{
  this.startPosition = route.startPosition;
  this.nodes = route.nodes;
  this.Add(nextPosition);
  this.findConnection();
}

新しいルートは、前のルートのノードへの参照のみを取得しますが、独自のノードリストが必要です。
だから私はそれをに変更しました

public Route(Route route, Position nextPosition)
{
  this.startPosition = route.startPosition;
  this.nodes.AddRange(route.nodes);
  this.Add(nextPosition);
  this.findConnection();
}

私はそれをもっと早く見たはずです。申し訳ありません!
しかしとにかくあなたの助けに感謝します!

于 2012-11-15T09:44:28.247 に答える