2010-02-04 2 views
3

Pour la vie de moi je ne peux pas donner un sens pourquoi ce code produit la sortie suivante ...C# Liste <T> .Find (x => x.Rectangle.Contains (point)) FAIL

Je pense qu'il est un bug ou quelque chose lorsque vous utilisez List et lambda si le type expose une propriété Rectangle et que vous utilisez la méthode Contains de l'objet rectangle ... et l'itération explicite est vraie alors que la méthode List Find échoue ....

Oneway

code

public GridSquare WorldToKeyPadSub(Point location) 
    { 
     location = _Map.WorldToClient(location); 
     GridSquare gs = this.Find(x => x.Rectangle.Contains(location)); 
     GridSquare kp = gs.Find(x => x.Rectangle.Contains(location)); 
     List<GridSquare> list = kp.FindAll(x=>x.Rectangle.Contains(location)); 
     u.dp(list.Count); 
     GridSquare sub = kp.Find(x => x.Rectangle.Contains(location)); 

     if (sub == null) 
     { 
      u.dp("Location to look for " + location); 
      u.dp("Found Location in grid square " + gs.ToString()); 
      u.dp("grid square bounds " + gs.Rectangle.ToString()); 
      u.dp("Found Location in Keypad " + kp.ToString()); 
      u.dp("key pad bounds " + kp.Rectangle.ToString()); 
      u.dp("Sub Key Pads Print All sub keys in this grid.keypad"); 
      foreach (GridSquare t in kp) 
      { 
       u.dp(t.ToString() + " " + t.Rectangle.ToString());     

      } 
      u.dp("Sub Key Pads Print Explicit Finds"); 
      foreach (GridSquare t in kp) 
      { 
       if (location.X >= t.Location.X 
        && location.Y >= t.Location.Y 
        && location.X <= t.Location.X + t.Rectangle.Width 
        && location.Y <= t.Location.Y + t.Rectangle.Height) 
       { 
        u.dp(true); 
        u.dp(t.ToString() + " " + t.Rectangle.ToString()); 
       } 

      } 
     } 
     return sub; 
    } 

Cela produit la sortie suivante ...

Remarquez comment l'explicite Rectangle (méthode aka Manuel) trouve les cases de la grille qui contiennent l'emplacement .... la maison la version GDI échoue ....

Location to look for {X=1476,Y=1716} 
Found Location in grid square GS: 14.3.0.0 
grid square bounds {X=1398,Y=1650,Width=100,Height=100} 
Found Location in Keypad GS: 14.3.6.0 
key pad bounds {X=1465,Y=1683,Width=33,Height=34} 
Sub Key Pads Print All sub keys in this grid.keypad 
GS: 14.3.6.7 {X=1465,Y=1683,Width=11,Height=11} 
GS: 14.3.6.8 {X=1476,Y=1683,Width=11,Height=11} 
GS: 14.3.6.9 {X=1487,Y=1683,Width=11,Height=11} 
GS: 14.3.6.4 {X=1465,Y=1694,Width=11,Height=11} 
GS: 14.3.6.5 {X=1476,Y=1694,Width=11,Height=11} 
GS: 14.3.6.6 {X=1487,Y=1694,Width=11,Height=11} 
GS: 14.3.6.1 {X=1465,Y=1705,Width=11,Height=11} 
GS: 14.3.6.2 {X=1476,Y=1705,Width=11,Height=11} 
GS: 14.3.6.3 {X=1487,Y=1705,Width=11,Height=11} 
Sub Key Pads Print Explicit Finds 
True 
GS: 14.3.6.1 {X=1465,Y=1705,Width=11,Height=11} 
True 
GS: 14.3.6.2 {X=1476,Y=1705,Width=11,Height=11} 
A first chance exception of type 'System.NullReferenceException' 

Répondre

6

Rectangle.Contains(Point) est exclusive (strictement moins-que) sur les limites supérieures du rectangle.

Pour exemple, le contrôle équivalent effectué par Rectangle.Contains(Point) dans votre contexte serait:

foreach (GridSquare t in kp) 
{ 
    if (location.X >= t.Location.X 
     && location.Y >= t.Location.Y 
     && location.X < t.Location.X + t.Rectangle.Width // < instead of <= 
     && location.Y < t.Location.Y + t.Rectangle.Height) // < instead of <= 
    { 
     u.dp(true); 
     u.dp(t.ToString() + " " + t.Rectangle.ToString()); 
    } 

} 

Comme vous pouvez le voir, il vérifie les limites supérieures comme strictement moins que, au lieu d'un inférieur ou égal, la différence entre votre méthode et Rectangle.Contains(Point) se trouve là.

L'emplacement passé dans votre {X est exemple = 1476, Y = 1716}, qui est passé à quand Contains de ces rectangles:

GS: 14.3.6.1 {X=1465,Y=1705,Width=11,Height=11} 
GS: 14.3.6.2 {X=1476,Y=1705,Width=11,Height=11} 

retournera false, lorsque le vôtre retourne vrai.

C'est la raison pour laquelle les kp.Find(x => x.Rectangle.Contains(location)); renvoie la valeur null, mais vos chèques manuels reviennent vrai.

+0

Je voudrais souligner ce qui est illégal ... Je suggère d'utiliser le Mono source comme référence. – Dykam

+1

Je suppose que votre point de vue pourrait être possible, mais je doute que l'association au Caire de Mono puisse faire du bien à quelqu'un qui ne l'utilise pas. –

0

Je vois deux choses que vous pouvez vérifier:

  1. Votre chèque explicite est inclus - moins-que-et-égaux, plus-que-et-égaux. Si Rectangle.Contains est exclusif, les deux points que votre vérification explicite trouve seront omis.

  2. Êtes-vous sûr que x.Location.X et .Y sont toujours les mêmes que x.Rectangle.X et .Y?

2

C'est ce que j'ai découvert ...

un instant sur un rectangle qui est défini 0,0,100,100 ...

On pourrait supposer que ce point 100100 est à l'intérieur de cette rectangle, mais ce n'est pas du tout le cas ...

Rectangle.Contains est exclusif des limites ... en d'autres termes, il ne retournera vrai que pour tous les points 0,0 à 99,99 dans un rectangle défini comme 0,0,100,100 ...

Le problème que j'ai eu, c'est que lorsque vous utilisez GDI pour dessiner ce rectangle ... les pixels sont attirés vers le bas et à droite ...

L'effet net est que Rectangle.Contains est inclus pour la partie supérieure et la branche gauche d'un rectangle, et exclusif pour les parties inférieure et droite du rectangle ... et d'un point de vue graphique .. et vous pouvez zoomer au niveau du pixel lors d'un test de hit avec une souris ...

Le curseur peut sembler être juste à l'intérieur de la limite du rectangle droite et vers le bas ... encore le test d'impact est renvoyer faux en raison de la nature exclusive de Rectangle .Contains pour le droit et les jambes en bas ...

SW