c#中接收方的有效返回值变为空



我刚开始接触c#,所以如果这是一个基本问题,请原谅我。我正在使用。net 4.0和VS 2010构建一个WPF应用程序。

我有一个类,我在其中存储对象的List;对象有一个Point对象作为字段。其中一个方法返回列表中特定位置的对象:

public Marker markerAtLocation(Point location) {
    foreach (Marker nextMarker in Markers)
        if (nextMarker.Location().Equals(location))
            return nextMarker;
    return null;
}

设置断点并使用Console.WriteLine,我已经确认nextMarker在返回时有效。然而,在接收器中,对象总是null:

Marker top = markerAtLocation(new Point(location.X, location.Y + 1));
if (top == null)
    Console.WriteLine("Top is null");
else
    Console.WriteLine("Top is " + top.ToString());
Marker bottom = markerAtLocation(new Point(location.X, location.Y - 1));
if ((bottom != null) && (bottom.player == otherPlayerType()) && (top != null) && (top.player == otherPlayerType()))
    return true;

我不知道这是怎么回事…

请注意,我最初认为这是。net的Point结构体使用双精度值的问题。我知道在我的应用程序中的位置值将始终是整数,所以我没有使用。net Point和创建我自己的:

class Point {
    public int X, Y;
    public Point(int X, int Y) {
        this.X = X;
        this.Y = Y;
    }
    public bool Equals(Point anotherPoint) {
        return ((anotherPoint.X == X) && (anotherPoint.Y == Y));
    }
}

我很感激任何帮助!

编辑:回应pbirkoff:

class Grid {
    public List<Marker> Markers;
    public Grid() {
        Markers = new List<Marker>();
    }
    public Grid(List<Marker> markers) {
        this.Markers = markers;
    }
    public void addMarker(Marker newMarker) {
        Markers.Add(newMarker);
    }

我已经尽我所能尝试了下面的解决方案,但没有一个有用。我包括一个链接到项目本身以及我试图解决的问题。

项目:http://dl.dropbox.com/u/7828009/ACSLPetteia.zip
问题:http://wcipeg.com/etc/ACSL/VOL%2030/ACSL%20Petteia_sr_3.doc

提前感谢!

我尽可能简洁地实现了您的代码,在适当的地方做了一些模拟(下面的代码),我不能让它失败。我的代码示例中缺少什么:

class Program
{
    static void Main(string[] args)
    {
        LoadMarkers();
        var location = new Point(45, 45);
        Marker top = markerAtLocation(new Point(location.X, location.Y + 1));
        if (top == null)
            Console.WriteLine("Top is null");
        else
            Console.WriteLine("Top is " + top.ToString());
        Marker bottom = markerAtLocation(new Point(location.X, location.Y - 1));
    }
    public static List<Marker> Markers = new List<Marker>();
    private static void LoadMarkers()
    {
        for (var q = 0; q < 50; q++)
            for (var w = 0; w < 50; w++)
                Markers.Add(new Marker(q, w));
    }
    public static Marker markerAtLocation(Point location)
    {
        foreach (Marker nextMarker in Markers)
            if (nextMarker.Location().Equals(location))
                return nextMarker;
        return null;
    }
}
class Marker
{
    private Point _loc;
    public Marker(int x, int y) { _loc = new Point(x, y); }
    public Point Location() { return _loc; }
}
class Point
{
    public int X, Y;
    public Point(int X, int Y)
    {
        this.X = X;
        this.Y = Y;
    }
    public bool Equals(Point anotherPoint)
    {
        return ((anotherPoint.X == X) && (anotherPoint.Y == Y));
    }
}

我将首先从更改类的名称开始。名称空间通常会处理任何冲突,但WPF点在System中定义。当尝试在WPF窗口类中创建Point时,Windows很可能会导致问题,我猜这是您的接收器代码所在的位置。我这么说的原因是,默认情况下,在自动生成的windows类VS创建的顶部会有一行"using System.Windows;"。

由于所有内容都派生自object,因此您也需要重写bool Equals(object o)函数,因为这将帮助您捕获与System.Windows.Point而不是您的Point进行比较的问题。

我想如果你把你的类名改为IntPoint,你可能会发现你的接收代码中的"new Point"可能不会被重构为"new IntPoint",因为它可能被解析为System.Windows.Point.

使用Grid作为名称也是如此。我尽量坚持不使用与。net类型名称匹配的类型名称的惯例,以避免奇怪的冲突。

所以总结一下,把你的类改成如下:
class IntPoint {
    public int X { get; set; }
    public int Y { get; set; }
    public IntPoint(int X, int Y) {
        this.X = X;
        this.Y = Y;
    }
    public override bool Equals(object obj)
    {
        if (obj is IntPoint) return Equals(obj as IntPoint);
        return base.Equals(obj);
    }
    public bool Equals(IntPoint anotherPoint) {
        return ((anotherPoint.X == X) && (anotherPoint.Y == Y));
    }
}

我还使用速记默认get/set语法将公共字段更改为公共属性。我不会深入到属性和字段的细节,但你可以在网上搜索。net属性和公共字段。部分原因与绑定的工作方式有关,. net允许您绑定到属性,但如果您试图绑定到其中一个字段,我相信它将无法找到它们。

如果你做了这些修改,但仍然不能正常工作,请发回。

可能与花括号有关(使用它们时可读性更强),尽管这可能不太可能。如果您将一个局部变量声明为函数的持有人,并返回该变量的存储值,该怎么办?这是否解决了问题,还是仍然表现出相同的行为?例如:

public Marker markerAtLocation(Point location) {
    Marker returnMarker = null;
    foreach (Marker nextMarker in Markers) {
       if (nextMarker.Location().Equals(location)) {
           returnMarker = nextMarker;
           break;
       } // end if
    } // end foreach
    return returnMarker;
} // end function

您是否100%肯定markerAtLocation返回非空标记。在调试中,你看到那行叫做??不,你没有看到它调用那行,因为你有它结构化调试的方式没有一行停下来看它"返回nextMarker()。这里有3层逻辑,没有{}。您确定您的代码像您期望的那样运行吗?

    foreach (Marker nextMarker in Markers)
    if (nextMarker.Location().Equals(location))
        return nextMarker;
        return null;

我怀疑发生了什么循环只到第二行。在最后且仅在最后一行,它继续返回nextMarker,并且只有当匹配在最后一行时才为真。清理你的逻辑——这不会有坏处。

    foreach (Marker nextMarker in Markers)
    {
        if (nextMarker.Location().Equals(location))
        {
            return nextMarker;
        }
    }
    return null;

我认为我们需要更多的信息(如Jon所要求的)来确定这里到底出了什么问题。

也许您正在使用静态函数并引用非静态项,例如您的公共类成员。这仍然可以编译和运行,尽管非静态变量在使用之前不会被初始化或设置。

最好将公共类变量实现为属性,例如public List<Marker> Markers{get;set;}而不是public List<Marker> Markers。Point类中的X和Y也是如此。

我的直觉是,你的一些类实例不再在范围内,或者因为它们是公共变量,它们可能已经被覆盖-尝试定义它们volatile -到你来引用它们的时候。

最新更新