首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何打破这个循环依赖关系

如何打破这个循环依赖关系
EN

Stack Overflow用户
提问于 2022-10-18 12:48:45
回答 2查看 78关注 0票数 2

我有两个类(房间,出口),我认为应该相互依赖,但这会导致循环依赖,这是一个不好的事情,从我的阅读。

代码语言:javascript
复制
//problem
public class Game
{
   public List<Room> Rooms {get; set;}
}

public class Room
{
   public Exit Exit {get; set;}
}

public class Exit
{
   public Room NextRoom {get; set;}
}

//Here is my solution

public class Game
{
   public List<Room> Rooms {get; set;}

   public Room GetNextRoom(Exit exit)
   {
      //Loops through the rooms list and compares Room.Id by Exit.NextRoomId and returns it
   }
}
public class Room
{
   public Exit Exit {get; set;}
}

public class Exit
{
   public string NextRoomId {get;set;}
}

我的问题是,我的解决办法是否有点正确,还是有更好的解决办法来解决这个问题。这打破了循环依赖关系,但在声明Exit对象时,它变得很难看,因为它通过字符串“引用”Room对象。

请记住,我不想实现一个接口或Eventhandler,我所读到的基本上只是一个创可贴的问题,并可能导致问题在未来。

EN

回答 2

Stack Overflow用户

发布于 2022-10-18 13:39:13

您所拥有的实际上是一个具有圈的有向图。你的模型是正确的-你不能摆脱周期。

但是,您不需要一个单独的“退出”类--您可以用一个名为(例如) List<Room>Exits属性来表示每个房间的出口。

旁白:由于出口实际上是“定向”的(即它们只指向下一个房间),以表示第1室和第2室之间的双向出口,因此必须单独添加每个出口。也就是说,在增加一个从1号房间到2号房间的出口时,你也必须增加一个从2号房间到1号房间的出口(当然,除非出口是单向的)。

您可以使用Newtonsoft.Json来序列化和反序列化这样的图表,同时考虑循环引用。

关键是您需要指定Json序列化选项PreserveReferencesHandling = PreserveReferencesHandling.All

另一个重要的事实是,您不能使用任何构造函数来设置类的属性,否则序列化/反序列化将失败。

这里有一个可编译的控制台应用程序来演示如何正确地完成它:

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using Newtonsoft.Json;

namespace ConsoleApp1
{
    static class Program
    {
        public static void Main()
        {
            var room1 = new Room { Name = "room1" };
            var room2 = new Room { Name = "room2" };
            var room3 = new Room { Name = "room3" };

            room1.Exits.Add(room2); room2.Exits.Add(room1);
            room2.Exits.Add(room3); room3.Exits.Add(room2);
            room3.Exits.Add(room1); room1.Exits.Add(room3);

            var jsonSettings = new JsonSerializerSettings
            {
                PreserveReferencesHandling = PreserveReferencesHandling.Objects
            };

            var serialised   = JsonConvert.SerializeObject(room1, jsonSettings);
            var deserialised = JsonConvert.DeserializeObject<Room>(serialised, jsonSettings)!;

            Console.WriteLine(deserialised.Name);                   // "room1"
            Console.WriteLine(deserialised.Exits[0].Name);          // "room2"
            Console.WriteLine(deserialised.Exits[0].Exits[1].Name); // "room3"
        }
    }

    public sealed class Room
    {
        public string Name { get; init; }
        public List<Room> Exits { get; } = new ();
    }
}

请注意,"room3“之外的打印使用Exits[1],因为这是最初连接的方式。

票数 3
EN

Stack Overflow用户

发布于 2022-10-18 13:29:49

如果一个出口没有其他属性或者任何房间没有的属性(我不知道为什么一个出口会和一个房间不同,因为出口只是一个指向下一个房间的指针,或者如果你在游戏结束时是空的),那么我就会这样做,在这个房间里有一个引用下一个房间的引用。注意:这假设一个房间只有一个出口,如果有多个见mathews答案。

代码语言:javascript
复制
    public class Game
    {
        public List<Room> Rooms { get; set; }
    }

    public class Room
    {
        public int RoomNumber { get; set; }
        public Room Exit { get; set; }
    }

然后你可以像这样使用它

代码语言:javascript
复制
    static void Main(string[] args)
    {
        Game game = new Game();
        game.Rooms = new List<Room>();

        Room firstRoom = new Room();
        Room exit = new Room();
        firstRoom.RoomNumber = 1;
        exit.RoomNumber = 2;

        firstRoom.Exit = exit;

        game.Rooms.Add(firstRoom);

        foreach(Room room in game.Rooms)
        {
            Console.WriteLine("Room:" + room.RoomNumber);
            Console.WriteLine("Exit:" + room.Exit.RoomNumber);
        }

        Console.ReadKey();
    }
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74111249

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档