c# - 如何打破这种循环依赖

标签 c# circular-dependency

我有两个类(Room、Exit),我认为它们应该相互依赖,但这会导致循环依赖,从我读到的内容来看,这是一件坏事。

//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 对象。

请记住,我不想实现接口(interface)或事件处理程序,我读到的这些基本上只是解决问题的创可贴,并且可能会在将来引起问题。

最佳答案

您所拥有的实际上是一个带有循环的有向图。你的模型是正确的 - 你无法摆脱循环。

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

旁白:因为导出实际上是“定向的”(即它们仅指向下一个房间)来表示房间 1 和房间 2 之间的双向导出,所以您必须单独添加每个导出。也就是说,在添加从房间 1 到房间 2 的导出时,还必须添加从房间 2 到房间 1 的导出(当然,除非导出是单向的)。

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

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

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

这是一个可编译的控制台应用程序,用于演示如何正确执行此操作:

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]因为这就是它最初的接线方式。

关于c# - 如何打破这种循环依赖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74111249/

相关文章:

c++ - 循环 C++ 头文件包括

c++ - 如何解析依赖类?

machine-learning - 机器学习算法中的循环数据

c# - 如果对象已被处置,抑制 gc 终结器是否可以节省一些时间?

c# - 调用链中的异步等待分配

c++ - 模板化循环继承

AngularJS 循环依赖

c# - 在 LINQ 中 JOIN 之后选择所有列

c# - 在文本框中输入字符的击键?

c# - long.TryParse 双值