13

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

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

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

我认为在 C# 中应该可以在实现时调用Disposeself,IDisposable但这不会破坏实例。

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

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

那么有没有什么办法,例如,摧毁自我?

4

8 回答 8

10

你的问题很有趣,我不知道在 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;
    }
}

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

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

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

于 2013-07-05T10:54:34.273 回答
3

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

于 2013-07-05T10:43:22.990 回答
2

不,没有办法实现您在C#.

如果你考虑一个例子:

public class Kamikadze {

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

     .....
}


var kamikadze = new Kamikadze ();

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

但是引用kamikadze(如果您愿意,可以使用指针)仍然有效并指向该内存位置,因此GC不会做任何事情,不会收集它,并且实例Kamikadze将保留在内存中。

于 2013-07-05T10:30:52.850 回答
1

对于 C++,看看这个: http: //www.parashift.com/c++-faq/delete-this.html

于 2013-07-05T10:39:29.223 回答
1

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

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

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

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

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

于 2013-07-05T12:45:18.957 回答
0

在 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...
于 2013-07-05T12:00:18.953 回答
0

在 C# 中,你是对的,你可以实现 IDisposable 但诀窍是使用 using 语句而不是调用 Dispose 方法。

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/using-statement

于 2019-08-02T13:05:38.860 回答
0

我建议使用NFTLKEY. 您可以轻松地从Nuget package. 最重要的是,它是开源的:github 项目

比这里的例子更容易理解

于 2021-07-27T18:53:51.803 回答