例如,是否可以销毁/删除自身
本文关键字:删除自身 是否 例如 | 更新日期: 2023-09-27 18:21:13
注意:我对C#、Java和C++最感兴趣,但这是任何语言都会遇到的更学术的问题。
我知道,通过使用给定语言的适当方法(调用free
、Dispose
或删除对实例的所有引用),这个问题可以从外部解决。
我的想法是创建一个实例,然后在构造函数中启动私有计时器。当计时器结束时,它将调用一些实例方法并销毁变量。
我认为在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项目
比这里的例子更容易理解