为了账号安全,请及时绑定邮箱和手机立即绑定

我应该假设每个拥有的实例都实现 IDisposable 吗?

我应该假设每个拥有的实例都实现 IDisposable 吗?

C#
慕尼黑5688855 2021-10-09 10:41:35
我正在开发我的小游戏项目,作为学习和练习 C# 的一种方式,但我遇到了一个设计问题。假设我们有以下一组类:interface IGameState{    //Updates the state and returns next active state    //(Probably itself or a new one)    IGameState Tick();}class Game{    public Game(IGameState initialState)    {        activeState = initialState;    }    public void Tick()    {        activeState = activeState.Tick();    }    IGameState activeState;}Game 基本上是 GameStates 的状态机。我们可以有MainMenuState,LoadingState或SinglePlayingState。但是添加MultiplayerState(代表玩多人游戏)需要一个套接字连接到服务器:class MultiplayerState : IGameState, IDisposable{    public IGameState Tick()    {        //Game logic...        //Communicate with the server using the Socket        //Game logic...        //Render the game        return this;//Or something else if the player quits    }    public void Dispose()    {        server.Dispose();    }    //Long-living, cannot be in method-scope    Socket server;//Or similar network resource}好吧,这是我的问题,我无法将它传递给它,Game因为它不知道它应该处理它,并且调用代码无法轻易知道游戏何时不再需要它。这个类设计几乎就是我到目前为止所实现的,我可以添加IDisposable,IGameState但我认为它不是一个好的设计选择,毕竟不是所有IGameState的都有资源。此外,这个状态机在某种意义上是动态的,任何活动IGameState都可以返回新状态。所以Game真的不知道哪些是一次性的,哪些是一次性的,所以它只需要测试一切。所以这让我问了几个问题:如果我有一个类对非密封类型的参数(例如initialState在游戏的 ctor 中)声明所有权,我应该总是假设它可以IDisposable吗?(可能不是)如果我有一个IDisposable实例,我是否应该通过强制转换到一个没有实现的基础来放弃它的所有权IDisposable?(可能没有)我从中收集到,IDisposable感觉像是一个非常独特的界面,具有显着的有损(*) 语义 - 它关心自己的生命周期。这似乎与提供有保证但非确定性内存管理的 GC 本身的想法直接冲突。我来自 C++ 背景,所以真的感觉它试图实现 RAII 概念,但是一旦有 0 个引用,就会手动调用 Dispose(destructor)。我并不是说这是对 C# 的咆哮,更像是我错过了某些语言功能?或者也许是 C# 特定的模式?我知道有,using但这只是方法范围。接下来是终结器,它可以确保调用 Dispose 但仍然不确定,还有其他的吗?也许像 C++' 这样的自动引用计数shared_ptr?正如我所说,上面的例子可以通过不同的设计解决(但我认为不应该),但没有回答可能不可能的情况,所以请不要过多关注它。理想情况下,我希望看到解决类似问题的一般模式。(*) 对不起,也许不是一个好词。但我的意思是,很多接口都表达了一种行为,如果类实现了所述接口,它只会说“嘿,我也可以做这些事情,但如果你忽略我的那部分,我仍然可以正常工作”。遗忘IDisposable不是无损的。我发现以下问题表明 IDisposable 通过组合传播,或者它可以通过继承传播。这对我来说似乎是正确的,需要更多的输入,但是可以。也正是这样MultiplayerState被感染了。但是在我的Game课堂示例中,它也想向上游传播,这感觉不对。最后一个问题可能是是否应该有任何有损接口,比如它是否是适合这项工作的工具,在这种情况下是什么?或者我知道还有其他常用的有损接口吗?
查看完整描述

1 回答

?
MYYA

TA贡献1868条经验 获得超4个赞

你所有的问题都是有效的讨论;但是,IDisposable如果您将它传递给一个类型,那么当您处于未知状态时,不知道该类型是否会正确处理它。因此,作为一项规则,一次性类型的原始所有者/初始化程序应始终负责处理。


所以在你的情况下,实例化的人MultiplayerState也负责处理它。如果您必须实例化它,然后将它传递给GameState并稍后处理它,那么MultiplayerState应该要求的原始所有者以某种方式跟踪它并正确处理它。


另外,在实现时,IDisposable我强烈建议将 disposing 添加到类的析构函数中。这是一个故障安全,以防一次性类型没有正确处理或正确实施。


例子:


 public void Dispose()

 {

      server.Dispose();

      GC.SuppressFinalize(this);

 }


 ~MultiplayerState() => Dispose()

我讲这个更在这里,如果你有兴趣。


查看完整回答
反对 回复 2021-10-09
  • 1 回答
  • 0 关注
  • 153 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信