【问题标题】:Scope confusion: how to split a single class C# project into multiple classes?范围混淆:如何将单个类 C# 项目拆分为多个类?
【发布时间】:2012-11-22 10:25:22
【问题描述】:

更新:请参阅底部的EDIT 3

我是 C# 和一般编程的初学者(所以请温柔一点!)。我遵循了大量的教程并阅读了书籍,并认为我理解了课程。到现在为止。

我有一个相当简单的单类项目,它使用一个 2D 字符串数组来设置一个 10x10 的字母 E(表示空)和 F(表示满)网格。我使用 int x 和 int y 来引用数组的坐标,并使用 switch 来检测输入并从 x 和 y 中加减来确定数组单元格是空还是满。

class MainGame
{
public MainGame()
{
    string[,] mapTerr = new string[10, 10]
    {
        { "F", "F", "F", "F", "F", "F", "F", "F", "F", "F" },
        { "F", "E", "E", "E", "E", "E", "E", "E", "E", "F" },
        { "F", "E", "E", "E", "E", "E", "E", "E", "E", "F" },
        { "F", "E", "E", "E", "E", "E", "E", "E", "E", "F" },
        { "F", "E", "E", "E", "E", "E", "E", "E", "E", "F" },
        { "F", "E", "E", "E", "E", "E", "E", "E", "E", "F" },
        { "F", "E", "E", "E", "E", "E", "E", "E", "E", "F" },
        { "F", "E", "E", "E", "E", "E", "E", "E", "E", "F" },
        { "F", "E", "E", "E", "E", "E", "E", "E", "E", "F" },
        { "F", "F", "F", "F", "F", "F", "F", "F", "F", "F" },
    }; // long-winded I know, but helps visualise the array
    int x, y;
    string navDir;
    Console.WriteLine("Enter a command:");
    navDir = Console.ReadLine();
    switch (navDir)
    {
        case "N":
        case "n":
            x -= 1;
            if (mapTerr[x, y] == "F")
            {
                Console.WriteLine("You cannot move North, it is blocked!");
                x += 1;
            }
            else
            {
                Console.WriteLine("You move North.");
            }
            break;
        case "E":
        case "e":
            y += 1;
            if (mapTerr[x, y] == "F")
            {
                Console.WriteLine("You cannot move East, it is blocked!");
                y -= 1;
            }
            else
            {
                Console.WriteLine("You move East.");
            }
            break;
        // etc...

这很好用。但是,我尝试将其拆分为单独的类:一个用于创建数组,另一个用于控制输入和输出。这是我的尝试:

class Program
{
    public static void Main(string[] args)
    {
        Map map = new Map();
        UserControl usercontrol = new UserControl();
    }
}

class Map
{
    string[,] mapTerr = new string[10, 10] {
    { // array contents here
    };
}

class UserControl
{
    int x, y;
    string navDir;

    public UserControl()
    {
        Console.WriteLine("Enter a command:");
        navDir = Console.ReadLine();
        switch (navDir)
        {
            case "N":
            case "n":
                x -= 1;
                if (mapTerr[x, y] == "F") // ERROR: The name 'mapTerr' does not exit in the current context"
                {
                    Console.WriteLine("You cannot move North, it is blocked!");
                    x += 1;
                }
                else
                {
                    Console.WriteLine("You move North.");
                }
                break;
            // etc...

我终其一生都无法弄清楚如何让它发挥作用。错误主要出现在从交换机内部调用数组时。

我意识到这是因为数组与 Map 类相关联,而不是与 UserControl 类相关联,那么如何使其可见/可用?

尽管在这里和其他地方在线搜索了数组/范围/类部分,但没有什么能真正用简单的术语完全解释事情。我认为这是一个范围问题,我试图以不可能的方式调用对事物的引用。如果有人能解释我做错了什么,或许可以暗示我可以以正确的方式处理事情,我将不胜感激! (为冗长的解释/问题道歉)

编辑 1:在该行旁边添加了特定的错误消息作为注释。这发生在开关中引用 mapTerr 的每一行。

编辑 2:阐明实例化和类结构。

编辑 3: 好的,字符串数组是在 Map 类中公开设置的,public string[,] elsaNav = new string[10, 10] {{/*contents*/}; 我在 Program 类中实例化了 map 类,但仍然无法调用 mapTerr 数组在 UserControl 类中,尽管使用了map.mapTerr...

【问题讨论】:

  • 您能否指出错误发生的那一行并向我们展示错误(通过编辑您的帖子)(PS:欢迎使用 StackOverflow :))

标签: c# class multidimensional-array scope


【解决方案1】:
public class Map
{
    public string[,] mapTerr = new string[10, 10] {
    { // array contents here
    };
}

public class UserControl
{
    int x, y;
    string navDir;
    Map myMap = new Map();

    public UserControl()
    {
        Console.WriteLine("Enter a command:");
        navDir = Console.ReadLine();
        switch (navDir)
        {
            case "N":
            case "n":
                x -= 1;
                if (myMap.mapTerr[x, y] == "F")
                {
                    Console.WriteLine("You cannot move North, it is blocked!");
                    x += 1;
                }
                else
                {
                    Console.WriteLine("You move North.");
                }
                break;
            // etc...

【讨论】:

  • 谢谢 - 我知道这会起作用。但是,我在 Program 类中实例化了 Map 类和 UserControl 类。正如我在下面对@AdamWhite 的评论中提到的那样,我可以从另一个类中访问在程序类中实例化的 Map 吗?我将编辑我上面的帖子以反映这一点。
  • 可以,如果设置为public的话。
  • 我已将 Map 类中的初始化数组设置为 public:public string[,] elsaNav = new string[10, 10] {{//contents}}; 并在我的 Program 类中对其进行了实例化,但我无法从 UserControl 类中调用它,尽管使用了map.mapTerr ...
【解决方案2】:

我不太确定在使用本文中给出的建议进行编辑后您的最终解决方案会是什么样子,但我已经修复了代码,为您提供了一种使用它的方法,希望它可以帮助您查明您的代码中的错误:)

using System.Collections;
using System;

class Program
{
    public static void Main(string[] args)
    {
        UserControl usercontrol = new UserControl();
    }
}

class Map
{
// Private map
private string[,] mapTerr;

// Public map
public string[,] MapTerr
{
    get {return mapTerr;}
}

public Map(int width, int height)
{
    mapTerr = new string[width, height];

    for (int x = 0; x < width; x++)
    {
        for (int y = 0; y < height; y++)
        {
            mapTerr[x,y] = "E";
        }
    }
}
}

class UserControl
{
    int x, y;
    string navDir;
Map map;

    public UserControl()
    {
        map = new Map(10, 10);
        Console.WriteLine("Enter a command:");
        navDir = Console.ReadLine();
        switch (navDir)
        {
            case "N":
            case "n":
            x -= 1;
            if (map.MapTerr[x, y] == "F") // ERROR: The name 'mapTerr' does not exit in the current context"
            {
                Console.WriteLine("You cannot move North, it is blocked!");
                x += 1;
            }
            else
            {
                Console.WriteLine("You move North.");
            }
            break;
        // etc...
        }
}
}

如果缩进有点不对,我很抱歉,我很着急,目前无法访问适当的 C# 编译器,但上面的代码应该可以工作 :)

顺便说一句,将地图和用户输入封装并分离到两个类中是个好主意!新程序员的良好开端:)

请记住在您的类中广泛使用属性来控制如何在您的类中访问数据成员。在大多数情况下,您不想让成员完全公开。相反,将它们设为私有并为它们创建一个属性,这样您就可以控制如何设置或访问数据。

当然,我刚刚快速编写了一些用字母初始化数组的示例逻辑,只是为了展示解决方案,所以您可能需要重新编写它以满足您自己的需要:)

此外,您希望如何使用地图对象还取决于您自己对客户端应如何使用代码的想法,我只是将地图对象作为 UserControl 类的组合,而不让客户端代码使用它。另一种方法当然是让客户端代码初始化自己的地图对象并将其传递给 UserInput 类的构造函数。

希望对你有帮助。

[编辑]

好的,字符串数组在Map类中公开设置,public string[,] elsaNav = new string[10, 10] {{/contents/};我在 Program 类中实例化了 map 类,但仍然无法从 UserControl 类中调用 mapTerr 数组,尽管使用了 map.mapTerr

好的,我还没有看到你的解决方案代码,但也许我仍然明白......让我试一试:P 基本上你是在 Program 类中实例化 Map 类,类似于:

Map myMap = new Map();

然后您尝试直接在 UserControl 类的实例中访问“myMap”引用?在这种情况下,您不能简单地这样做。 myMap 引用仅在您从中调用它的 Program 类方法的范围内,因此当您尝试从 UserControl 类中引用它时,它不会有任何关于它的知识,它都超出了它的范围。相反,您必须像这样将引用传递给 UserControl 类:

Map myMap = new Map();

UserControl newControl = new UserControl(myMap);

然后在类中,您的构造函数将如下所示:

    public UserControl(Map map)
    {
        map.MapTerr... etc
    }

也许我误解了你的意思,但如果这是你的意思,那么上面的解决方案应该可以解决它:)

【讨论】:

  • 很棒的答案,非常感谢! Edit 下面的建议是最容易在我的代码中实现的,并且在引用方面很有意义。但是,在您看来,您对使用属性的第一个建议会是一种更好/更可取的工作方式吗?
  • 很高兴能帮上忙!好吧,哪种方式更可取完全取决于您认为客户端代码应该如何与这两个部分一起工作:) 您必须记住的编程和设计的一件事是 之间并不总是有明显的区别对,尽管根据情况可能会有更可取和更优雅的方式来做这件事。我只是将 Map 类隐藏在 UserControl 输入中,因为我看不出客户端代码必须担心该对象的任何原因,即必须对其进行初始化然后将其传递给 UserControl :)
【解决方案3】:

您还没有实例化地图类。

在 public UserControl() 中,您需要添加一些类似 Map map = new Map();

然后通过map.mapTerr[x, y]访问mapTerr

例如,请查看上面 Dejo 的回复。

【讨论】:

  • 抱歉,我没有提到我确实在主类“程序”(不包括在上面)中实例化了 Map 类(和 UserControl)。我尝试通过map.mapTerr 访问mapTerr,但Map map = new Map(); 似乎仍然仅限于它被实例化的类。
【解决方案4】:

您的主要问题是 mapTerr 的默认保护级别是 Map 私有的。其次,即使它是公开的,你仍然需要进一步限定它,要么通过 Map 的实例化实例,要么将其设为静态:

static class Map
{
    public static readonly string[,] mapTerr = new string[10,10 {...}
}

要引用您需要完全限定属性:

class UserControl
{
    public UserControl()
    {
        ...
        if (Map.mapTerr[x,y] == "F")
        { 
            ...
        }
    }
}

您还应该考虑 1) 将公共字段隐藏在属性后面,以及 2) 将字符串更改为字符。

【讨论】:

    猜你喜欢
    • 2011-12-22
    • 2020-02-28
    • 2013-11-09
    • 1970-01-01
    • 2016-06-06
    • 1970-01-01
    • 2012-08-09
    • 2013-06-18
    • 1970-01-01
    相关资源
    最近更新 更多