我有这个示例代码,它是不完整的,因为我不知道如何做我想要做的事情.

    // This class will never be garbage collected
    // It is the core to my Game Engine Loop.
    public class Application
    {
        HybridObject obj1;
        HybridObject obj2;
        List<Test> tests = new List<Test>();

        public Application()
        {
            obj1 = new HybridObject();
            obj2 = obj1;

            for (int i = 0; i < 1000; i++)
            {
                Test test = new Test();
                test.obj = obj1;
                tests.Add(test);
            }

            obj1.Delete(); // This line should Null all properties using obj1 as a value.

            while (true)
            {
                CheckIfNull();
            }
        }

        void CheckIfNull()
        {
            if (obj1 == null) Console.WriteLine("Destroyed 1");
            if (obj2 == null) Console.WriteLine("Destroyed 2");

            foreach (var t in tests)
            {
                if (t.obj == null)
                {
                    Console.WriteLine("Destroyed From List");
                }
            }
        }
    }
    public class Test
    {
        public HybridObject obj;
    }
    public class HybridObject
    {
        public void Delete()
        {
            // SET ALL REFERENCES THAT POINT TO THIS HYBRIDOBJECT TO NULL
        }
    }

Smaller Example

如果我们只是抽象出我的代码的乱七八糟的部分.问题可以归结为,在下面的示例中,如何将使用obj的所有内容设置为空?

HybridObject obj = new HybridObject();
List<HybridObject > objects = new List<HybridObject>();
objects.Add(obj);
objects.Add(obj);
obj = null; // If I set this all obj's in the list would be null as well.

Explanation

现在让我解释一下,我正在制作一个基本的游戏引擎.

我正在try 使用Delete方法将我创建的HyBridge Object的所有引用设置为空.当我调用obj1.Delete()时,因为我将obj1属性设置为新的HyBridge Object(),然后将所有其他属性值(如obj2)设置为obj1,所以需要将‘Application’obj1、obj2属性和所有‘Test’obj属性设置为空.

当我调用obj1.Delete()时,指向(Obj1)HyBridge Object的所有内容现在都应该变为空.然后,由于没有更多的引用,HyBridge Object最终可以被垃圾回收.设置obj1=NULL;不能解决这个问题,因为它不会将其他引用设置为NULL.

Obj1属性可以传递到任何地方,比如传递到另一个类属性、列表、 struct 等.那么,在不手动跟踪所有引用的情况下,我该如何处理将所有内容设置为空呢?HyBridge Object永远不会被销毁,因为仍然会有对它的强引用.

那么,如果在我的应用程序运行时,我随着时间的推移创建了数百万个对象,但没有一个对象因为它们持有的强引用而被销毁,那又如何呢?如果随着时间的推移,我在应用程序‘obj1’中创建的一个HyBridge Object被传递到数百万个其他位置,比如集合,会发生什么呢?(当然,这都是理论上的).

问题是.如何删除指向某个对象的所有引用或指针,以便对其进行垃圾回收?我甚至不确定这是否可能.

Things I have tried

  1. 我找到了一个使用反射的解决方案,但当考虑到HyBridge Object如何存储(如属性、集合、 struct 等)时,它变得非常复杂,然后它必须在运行时运行我创建的每个对象实例.它不是很快,所以我认为这不是一个好主意.

  2. try 在HyBridge Object中创建一个对象实例属性,然后使所有内容都引用该实例属性,当我将该实例属性设置为空时,我希望指向该实例属性的所有内容都反映该更改并变为空.但我不能让它工作.

推荐答案

我很喜欢使用Unity,它允许这种类型的行为

Unity是一个完全不同的运行时,空值判断实际上并不判断引用是否是空值引用(即,它指向"空内存")--例如,参见this answer,即1)这并不意味着对象占用的所有内存都可以GCed(因此,您在"普通"C#中可能遇到的所有问题都是您试图避免的)2)this == null(see this SO question)可以得到true,这在"普通"C#的观点下是没有太大意义的.

如果只判断If Object!=NULL,则很容易避免.

如果你所要求的是可能的,那就不容易避免了.尤其是在多线程环境中.因此,如果任何引用在任何时刻都可以被作废,则无法保证在判断之后该引用实际上不是空的(除非使用某种魔力锁定,这可能会扼杀所有性能并导致死锁).

因此,总而言之,对于继承了UnityEngine.Object的任何东西,与NULL的比较并不意味着您认为它实际上意味着什么,所以您可以考虑以下选项:

  1. 遵循Unity中的模式-公开的API类是内部资源的包装器,可以清除这些资源,并使用自定义==创建基类,这将"假"为空值.
    • 就我个人而言,我会考虑使用IDisposable模式(可能与通常的实现略有不同--当对Disposed对象调用某个对象时不抛出,而是使其成为无操作的对象,但这是有争议的)
  2. 设计一些API来为obj1.OnDelete注册一些回调,这样用户代码就可以做必要的事情,尽管我认为它很快就会变得太麻烦
  3. 由于您将需要依赖开发人员以某种方式进行清理(例如,发布对"包装器"的引用),因此至少对于一些基本的游戏引擎而言,完全依赖它可能是值得的.

阅读更多内容:

Csharp相关问答推荐

ASP.NET MVC购物车数量更新并从购物车中删除项目

EF Core判断是否应用了AsSplitQuery()

如何注销Microsoft帐户?

如何模拟耐久任务客户端在统一测试和获取错误在调度NewsListationInstanceAsync模拟设置

从应用程序图API调用访问所有者字段

为什么任务需要在内部使用ManualResetEventSlim?

默认情况下,.NET通用主机(Host.CreateDefaultBuilder)中是否包含UseConsoleLifetime?

如何将不同类型的扩展参数的javascript函数转换成C#风格?

如何忽略API JSON响应中的空字符串?

SortedSet.Remove()不会删除SortedSet.Min返回的元素

try 在.Net核心身份注册页面中使用AJAX,但没有成功..NET Core 5.0 Razor页面应用程序

显示文档的ECDsa签名PDF在Adobe Reader中签名后已被更改或损坏

如何使用.NET6WPF打印车票?

等待一个等待函数

如何使用用于VS代码的.NET Maui扩展在我的iOS/Android设备或模拟器上进行调试?

记录类型';==运算符是否与实现IEquatable<;T&>;的类中的';equals&>方法执行等价比较?

Blazor:搜索框在第一次搜索时不搜索

基于C#方法的EF核心过滤查询(缓冲与流)

C#命名管道-编码错误?

如何对正方形格线进行对角分组