在 C# 中的另一个对象中实例化用户定义的对象

Instantiating User Defined Object inside Another Object in C#

我在应用程序中存储 objects/data 的方式需要一些帮助。我正在创建一个应用程序:创建一个机器人,将任务分配给机器人,显示带有任务时间的机器人信息等。

当程序 运行 时,我已经设置了多个要在 Main 中实例化的不同对象。然后用户将从类型列表中 select 一个机器人类型。我无法将 botType 对象传递到 Robot 对象。我要求用户使用 int select botType 1-6,然后我希望用户 selected int 定义应将哪个 botType 应用于机器人。 因为我在 Main 中初始化 BotType,然后使用与 CreateRobot() 不同的方法。我无法将 botType 传递到 Robot 对象。我可以将整数传递给用户 selects 但这并没有像我试图完成的那样将 botType 传递给 Robot..

这是我的 classes/constructors 正在使用:

  public class Robot
    {
        //Store robot name
        public string botName { get; set; }

        //Store robot type
        public BotType botType { get; set; }

        //Store time to complete task
        public int timeElapsed { get; set; }

        public Robot(string BotName, BotType botType, int TimeElapsed)
        {
            this.botName = BotName;
            this.botType = new BotType();
            timeElapsed = TimeElapsed;
        }

    public class BotType
        {
    
            //Type of robot
            public string TypeName { get; set; }
            //Type of task represented by number
            public int TaskType { get; set; }
    
            //contructor to set values
            public BotType (string typeName, int taskType)
            {
                TypeName = typeName;
                TaskType = taskType;
            }

然后是初始化对象的主要方法,但是当我尝试使用它们时,我无法像我希望的那样将用户定义的 int 转换为 BotType..

public class BotOMat
    {
        public static List<Robot> botList = new List<Robot>();
        public static List<BotTask> botTaskMap = new List<BotTask>();
        public static List<BotType> botTypeMap = new List<BotType>();


        static void Main(string[] args)
        {
            //initalize bot types
            BotType UNIPEDAL = new BotType("Unipedal", 1);
            BotType BIPEDAL = new BotType("Bipedal", 2);
            BotType QUADRUPEDAL = new BotType("Quadrupedal", 3);
            BotType ARACHNID = new BotType("Arachnid", 4);
            BotType RADIAL = new BotType("Radial", 5);
            BotType AERONAUTICAL = new BotType("Aeronautical", 6);

            //initialize bot tasks
            BotTask DISHES = new BotTask("Do the dishes", 1000, 0);
            BotTask SWEEP = new BotTask("Sweep the house", 3000, 0);
            BotTask LAUNDRY = new BotTask("Do the laundry", 10000, 0);
            BotTask RECYCLING = new BotTask("Take out the recycling", 4000, 0);
            BotTask SAMMICH = new BotTask("Make a sammich", 7000, 0);
            BotTask LAWN = new BotTask("Mow the lawn", 20000, 0);
            BotTask RAKE = new BotTask("Rake the leaves", 18000, 0);
            BotTask BATH = new BotTask("Give the dog a bath", 14500, 0);
            BotTask BAKE = new BotTask("Bake some cookies", 8000, 0);
            BotTask WASH = new BotTask("Wash the car", 20000, 0);

            var botTaskMap = new List<BotTask> { DISHES, SWEEP, LAUNDRY, RECYCLING, SAMMICH, LAWN, RAKE, BATH, BAKE, WASH };
            var botTypeMap = new List<BotType> { UNIPEDAL, BIPEDAL, QUADRUPEDAL, ARACHNID, RADIAL, AERONAUTICAL };

private static void createRobot()
        {

            //Get robot name, add to list saving multiple names.
            Console.WriteLine("Enter robot name:");
            string botName = Console.ReadLine();

            //Get robot type
            Console.WriteLine("Enter robot type: (number)");
            int botType = Convert.ToInt32(Console.ReadLine());
            //botType = botTypeMap[botType];
            
            //boxing to convert int to BotType

            //error handling 
            if (botType < 1 || botType > 6)
            {
                Console.WriteLine("Invalid input. Please enter number 1-6.");
                //BotType.TaskType = 0;
            }

            //Add robot to the class storing robot information.
            if (botType > 1 || botType < 6)
            {
                
                Robot aRobot = new Robot(botName, botType, 0);
                botList.Add(aRobot);
                aRobot.AssignBotTask();
                aRobot.CompleteTask();

            }
            else
            {
                MainMenu();
            }

        }

我可以将 BotType 作为整数传递给 Robot 或接收参数 2:无法从 int 转换为 BotOMat.BotType。每当我尝试使用 aRobot 写入任何输出时,控制台正在使用受保护的变量写入,这不是所需的输出。

我应该在机器人 class 中创建一个机器人吗?然后我需要稍后将 BotTask(s) 分配给机器人......我相信它们使用关联类型关系但是如果对象没有在每个 class 中初始化。我不确定如何开始;例如:洗碗的独足机器人。

我提前感谢任何帮助。我试图尽可能描述而不张贴重复问题,因为我能找到的任何其他示例比我认为的要基本得多我正在努力完成这里。

下次 post 提问时,您应该查看帮助,尤其是关于准备最小可重现示例的帮助。您的代码无法编译,您缺少类型、函数等。我将在下面展示的一些内容与您展示的内容不太相符,但它似乎确实符合您的意图(至少对我而言) .

我将从底层开始,然后向上推进。您的 BotType class 仅包含一个字符串和一个整数(整数递增)。我将不使用 class,而是使用 enum(您应该仔细阅读这些内容)。枚举是值类型。在幕后,它们最终由一个简单的整数值类型(如 int)表示,但是对于它们包含的元数据,它们也有一个符号名称。所以:

public enum RobotType
{
    Unipedal = 1,
    Bipedal,
    Quadrupedal,
    Arachnid,
    Radial,
    Aeronautical,
}

如果我没有包含 =1,那么 Unipedal 将以默认值(零)开始。您将在下面看到为什么从一个开始是有意义的。枚举的好处是您可以将它们转换为整数,或转换为表示其符号的字符串。您还可以将包含整数的字符串或包含符号名称的字符串解析为枚举实例:

var asInt = (int) RobotType.Unipedal;
var asString = RobotType.Unipedal.ToString();
bool isGoodParse = Enum.TryParse<RobotType>("1", out RobotType parsedFromInt);
isGoodParse = Enum.TryParse<RobotType>("Unipedal", out RobotType parsedFromString);

所有代码都按照您预期的方式工作。

很容易对您的任务类型做同样的事情。但名称不是有效的 C# 符号(它们有空格)。相反,我们将使用 System.ComponentModel.DescriptionAttribute 向枚举值添加一些额外的元数据:

public enum RobotTaskName
{
    [Description("Do the dishes")]
    DoTheDishes = 1,
    [Description("Sweep the house")]
    SweepTheHouse,
    [Description("Do the laundry")]
    DoTheLaundry,
    [Description("Take out the recycling")]
    TakeOutTheRecycling,
    [Description("Make a sammich")]
    MakeASammich,
    [Description("Mow the lawn")]
    MowTheLawn,
    [Description("Rake the leaves")]
    RakeTheLeaves,
    [Description("Give the dog a bath")]
    GiveTheDogABath,
    [Description("Bake some cookies")]
    BakeSomeCookies,
    [Description("Wash the car")]
    WashTheCar,
}

但是,现在我们不能只对枚举值调用 ToString 来获取相应的名称。相反,我们将使用反射从 Description 属性中提取名称:

public static class RobotExtensions
{
    public static string GetDescription<T>(this T enumValue) where T : struct, Enum
    {
        var enumInfo = typeof(T).GetField(enumValue.ToString());
        if (enumInfo != null)
        {
            var attributes = enumInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
            if (attributes != null && attributes.Length > 0)
            {
                return ((DescriptionAttribute[])attributes)[0].Description;
            }
        }
        //otherwise
        return enumValue.ToString();
    }
}

该代码为枚举声明了一个扩展方法(您可以直接在枚举上调用它——任何枚举)。它反映了枚举值的 字段信息 ,检查它是否具有 DescriptionAttribute。如果是,它会挖掘出描述并 returns 它。如果它无法获得该信息,它只是 returns enumValue.ToString。结果:

RobotTaskName.DoTheDishes.GetDescription();   //returns "Do the dishes"
RobotType.Arachnid.GetDescription();          //returns "Arachnid"

这样做的另一件很酷的事情是,我们可以编写一些代码来提示用户输入特定的枚举值、检查其有效性等:

public static T? GetResponseUsingEnum<T>(string prompt) where T : struct, Enum
{
    //Loop until a good answer (or no answer)
    while (true)
    {
        Console.WriteLine($"{prompt}: Please enter one of:");
        var values = (T[])Enum.GetValues(typeof(T));
        foreach (var enumValue in values)
        {
            var description = enumValue.GetDescription<T>();
            var intValue = Convert.ToInt32(enumValue);
            Console.WriteLine($"{intValue}: {description}");
        }
        Console.Write(">> ");
        var response = Console.ReadLine();
        if (string.IsNullOrEmpty(response))
        {
            return (T?)null;
        }
        if (Enum.TryParse<T>(response, out var val))
        {
            if (values.Contains(val))
            {
                Console.WriteLine($"You answered: {val}");
                return val;
            }
        }
    }
}

该代码显示特定枚举类型的所有值的整数和字符串表示形式,然后提示用户输入一个值。如果用户输入的值超出范围,则它会重新提示 him/her。如果用户只是点击 Enter,那么它将 returns 一个 null 值。否则,如果用户输入有效答案,它 returns 答案(不是整数,而是正确键入的枚举项。

现在底层已经完成,让我们继续努力......

我不太清楚你的机器人任务类型是做什么的,或者额外的两个整数在哪里,所以我称它们为 Num1Num2。我还添加了一个 Perform 函数来“执行”任务(将其回显到控制台)。

public class BotTask
{
    public RobotTaskName Name { get; set; }
    public string Description => Name.GetDescription();
    public int Num1 { get; set; }
    public int Num2 { get; set; }

    public BotTask(RobotTaskName name, int num1, int num2)
    {
        Name = name;
        Num1 = num1;
        Num2 = num2;
    }

    public void Perform()
    {
        Console.WriteLine($"  - Peforming Task: {Name.GetDescription()} with {Num1} and {Num2}");
    }
}

如果你很好奇,Description 属性 是一个 只读 属性 调用 GetDescription底层 RobotTaskName 枚举类型。

然后我重新创建了您的 Robot 类型。我不知道您对 TimeElapsed 属性 的意图是什么。但是,我将其从 int 更改为 TimeSpan - 因为,这就是 TimeSpan 的用途。

public class Robot
{
    public string BotName { get; set; }

    public RobotType BotType { get; set; }
    public string BotTypeDescription => BotType.GetDescription();

    public TimeSpan TimeElapsed { get; set; }

    private List<BotTask> _tasks = new List<BotTask>();
    public IEnumerable<BotTask> Tasks => _tasks;

    public Robot(string botName, RobotType botType, TimeSpan timeElapsed = default)
    {
        this.BotName = botName;
        this.BotType = botType;
        TimeElapsed = timeElapsed;
    }

    public void AddTask (BotTask task)
    {
        _tasks.Add(task);
    }

    public void Show()
    {
        Console.WriteLine($"Robot: {BotName}, Type: {BotTypeDescription}, TimeElapsed: {TimeElapsed}");
        foreach (var task in Tasks)
        {
            task.Perform();
        }
    }
}

请注意,我还添加了已分配给每个机器人的任务列表。这包括列表、向机器人添加任务的 AddTask 方法等

最后,我向 Robot class 添加了一个 Run 方法来触发整个事件(从 Main 调用它)。它允许您创建多个机器人并为每个机器人分配多个任务。它使用 GetResponseUsingEnum 方法来获取机器人类型和任务类型。这意味着一致的用户界面和一些健康的代码重用(如果您发现该功能中的错误,您可以修复两个功能)。

public static void Run()
{
    var robotsList = new List<Robot>();
    //loop until there are no more robots
    while (true)
    {

        Console.Write("Enter robot name: ");)
        var robotName = Console.ReadLine();
        if (string.IsNullOrEmpty(robotName))
        {
            break;  //empty robot, time to list things out
        }

        RobotType? robotType = null;
        while (!robotType.HasValue)
        {
            robotType = GetResponseUsingEnum<RobotType>("Robots");
        }

        var robot = new Robot(robotName, robotType.Value);
        robotsList.Add(robot);
        Console.WriteLine("Time to add some tasks for this robot");

        //get tasks - loop until no more tasks
        while (true)
        {
            var taskName = GetResponseUsingEnum<RobotTaskName>("RobotTaskName");
            if (!taskName.HasValue)
            {
                break;  //no more tasks
            }
            var task = new BotTask(taskName.Value, 100, 200);
            robot.AddTask(task);
        }
    }

    //At this point, we have a fully populated list of robots, each with some tasks
    foreach (var robot in robotsList)
    {
        robot.Show();
    }
}

最后,如果你 运行 它,输出如下所示:

Enter robot name: Robby
Robots: Please enter one of:
1: Unipedal
2: Bipedal
3: Quadrupedal
4: Arachnid
5: Radial
6: Aeronautical
>> 2
You answered: Bipedal
Time to add some tasks for this robot
RobotTaskName: Please enter one of:
1: Do the dishes
2: Sweep the house
3: Do the laundry
4: Take out the recycling
5: Make a sammich
6: Mow the lawn
7: Rake the leaves
8: Give the dog a bath
9: Bake some cookies
10: Wash the car
>> 2
You answered: SweepTheHouse
RobotTaskName: Please enter one of:
1: Do the dishes
2: Sweep the house
3: Do the laundry
4: Take out the recycling
5: Make a sammich
6: Mow the lawn
7: Rake the leaves
8: Give the dog a bath
9: Bake some cookies
10: Wash the car
>> 3
You answered: DoTheLaundry
RobotTaskName: Please enter one of:
1: Do the dishes
2: Sweep the house
3: Do the laundry
4: Take out the recycling
5: Make a sammich
6: Mow the lawn
7: Rake the leaves
8: Give the dog a bath
9: Bake some cookies
10: Wash the car
>>
Enter robot name: SecondRobot
Robots: Please enter one of:
1: Unipedal
2: Bipedal
3: Quadrupedal
4: Arachnid
5: Radial
6: Aeronautical
>> 3
You answered: Quadrupedal
Time to add some tasks for this robot
RobotTaskName: Please enter one of:
1: Do the dishes
2: Sweep the house
3: Do the laundry
4: Take out the recycling
5: Make a sammich
6: Mow the lawn
7: Rake the leaves
8: Give the dog a bath
9: Bake some cookies
10: Wash the car
>> 8
You answered: GiveTheDogABath
RobotTaskName: Please enter one of:
1: Do the dishes
2: Sweep the house
3: Do the laundry
4: Take out the recycling
5: Make a sammich
6: Mow the lawn
7: Rake the leaves
8: Give the dog a bath
9: Bake some cookies
10: Wash the car
>> 10
You answered: WashTheCar
RobotTaskName: Please enter one of:
1: Do the dishes
2: Sweep the house
3: Do the laundry
4: Take out the recycling
5: Make a sammich
6: Mow the lawn
7: Rake the leaves
8: Give the dog a bath
9: Bake some cookies
10: Wash the car
>>
Enter robot name:
Robot: Robby, Type: Bipedal, TimeElapsed: 00:00:00
  - Peforming Task: Sweep the house with 100 and 200
  - Peforming Task: Do the laundry with 100 and 200
Robot: SecondRobot, Type: Quadrupedal, TimeElapsed: 00:00:00
  - Peforming Task: Give the dog a bath with 100 and 200
  - Peforming Task: Wash the car with 100 and 200