例如,是否可以销毁/删除自身

本文关键字:删除自身 是否 例如 | 更新日期: 2023-09-27 18:21:13

注意:我对C#、Java和C++最感兴趣,但这是任何语言都会遇到的更学术的问题。

我知道,通过使用给定语言的适当方法(调用freeDispose或删除对实例的所有引用),这个问题可以从外部解决。

我的想法是创建一个实例,然后在构造函数中启动私有计时器。当计时器结束时,它将调用一些实例方法并销毁变量。

我认为在C#中,当实现IDisposable时,应该可以在self上调用Dispose,但这不会破坏instance。

在C++中,我可以调用destructor,但这会导致内存泄漏,而且这是一种非常糟糕的做法。

在Java中,我不知道分配给this是不可能的,因为它是final字段。

那么,有什么方法可以摧毁自我吗?

例如,是否可以销毁/删除自身

您的问题非常有趣,我不知道在C#中有什么其他方法可以做到这一点,只能从实例内部强制从外部销毁它。所以这就是我想出来检查是否可能的。您可以创建类Foo,该类具有在计时器的特定间隔过去时激发的事件。在事件中注册到该事件(Bar)的类取消注册该事件,并将实例的引用设置为null。这就是我要做的,经过测试和工作。

public class Foo
{
    public delegate void SelfDestroyer(object sender, EventArgs ea);
    public event SelfDestroyer DestroyMe;
    Timer t;
    public Foo()
    {
        t = new Timer();
        t.Interval = 2000;
        t.Tick += t_Tick;
        t.Start();
    }
    void t_Tick(object sender, EventArgs e)
    {
        OnDestroyMe();
    }
    public void OnDestroyMe()
    {
        SelfDestroyer temp = DestroyMe;
        if (temp != null)
        {
            temp(this, new EventArgs());
        }
    }
}
public class Bar
{
    Foo foo;
    public Bar()
    {
        foo = new Foo();
        foo.DestroyMe += foo_DestroyMe;
    }
    void foo_DestroyMe(object sender, EventArgs ea)
    {
        foo.DestroyMe -= foo_DestroyMe;
        foo = null;
    }
}

为了测试这一点,你可以在Form中设置一个按钮点击,类似这样,并在调试器中检查它:

Bar bar = null;
private void button2_Click(object sender, EventArgs e)
{
       if(bar==null)
             bar = new Bar();
}

因此,下次单击按钮时,您将能够看到Bar实例仍然存在,但其中的Foo实例为null,尽管它是在Bar的构造函数中创建的。

C++:如果一个对象是动态分配的,它可以在自己的函数中删除它的this指针,前提是该指针在该点之后不再使用。

不,没有办法实现您在C#中要做的事情。

如果你考虑一个例子:

public class Kamikadze {
     ......             
     private void TimerTick(..) 
     {
        ....
        if(itsTime) {
            DestroyMe();
        }
     }
     .....
}

var kamikadze = new Kamikadze ();

过一段时间,DestroyMe()将被调用,将清理内部数据。

但是引用kamikadze指针,如果您愿意的话)仍然有效,并且指向该内存位置,因此GC不会执行任何操作,不会收集它,并且Kamikadze的实例将保留在内存中。

对于C++,请查看以下内容:http://www.parashift.com/c++-常见问题/deletethis.html.

我能想到的C#中最接近的东西:

在创建时,每个对象都在GC根中存储对其自身的引用,例如,将引用放入类静态列表中。在类之外,任何人都不允许存储对对象的(强)引用。每个人都使用WeakReference,并在触摸对象之前检查Target是否仍然是IsAlive。这样,唯一能使对象保持活动状态的就是静态引用。

当对象决定杀死自己时,它只是从列表中删除引用。GC迟早会收集对象。或者,如果你真的很不耐烦,打电话给GC.Collect()(哎哟!)。

但我真的非常不推荐这个解决方案!

最好在类/对象中放入一些标志来表示它是否仍然存在,并让每个人在使用对象之前都检查这个标志。这可以与IDisposable解决方案相结合。

在C++中,自杀实例是有限状态机模式的一个组成部分:

//Context class contains a pointer to a State object.
void BattleshipGame::SetGameState(IState* state) {
    game_state = state;
}
void BattleshipGame::Loss() {
    game_state->Loss(this);
}
void BattleshipGame::Idle() {
    game_state->Idle(this);
}
void BattleshipGame::FlyBy() {
    game_state->FlyBy(this);
}
void BattleshipGame::Attack() {
    game_state->Attack(this);
}
void BattleshipGame::Win() {
    game_state->Win(this);
}
void BattleshipGame::Load() {
    game_state->Loading(this);
}
//State base class contains methods for switching to every state.
class IState {
public:
    virtual void Loading(BattleshipGame* context);
    virtual void Idle(BattleshipGame* context);
    virtual void FlyBy(BattleshipGame* context);
    virtual void Attack(BattleshipGame* context);
    virtual void Win(BattleshipGame* context);
    virtual void Loss(BattleshipGame* context);
protected:
private:
};
//Implementations in the State base class are defined, but empty.
//Derived States only call what they need:
void StateIdle::Loss(BattleshipGame* context) {
    //context->SetGameState(new StateLoss());
    context->SetGameState(new StateLoss(context));
    delete this;
}
void StateIdle::Idle(BattleshipGame* context) {
    context->SetGameState(new StateIdle());
    delete this;
}
void StateIdle::FlyBy(BattleshipGame* context) {
    context->SetGameState(new StateFlyBy());
    delete this;
}
void StateIdle::Win(BattleshipGame* context) {
    context->SetGameState(new StateWin());
    delete this;
}
//Similar design for all other states...

在C#中,您可以实现IDisposable,这是正确的,但诀窍是不要调用Dispose方法,而是使用using语句。

class Program
{
    static void Main(string[] args)
    {
        using (MyClass obj = new MyClass())
        {
            obj.SayHello();
        }
        // obj.SayHello(); // Error: The name 'obj' does not exist in the current context
    }
}
class MyClass : IDisposable
{
    public void SayHello()
    {
        Console.WriteLine("Hello");
    }
    public void Dispose()
    {
        // Do something (e.g: close some open connection, etc)
    }
}

供参考:microsoft docs/使用语句

我建议使用NFTLKEY。你可以很容易地从Nuget package上得到它。最棒的是,它是开源的:github项目

比这里的例子更容易理解