注意:我最感兴趣的是C#,Java和C ++,但这是任何语言都会提出的学术问题。
我知道这个问题可以通过使用给定语言的适当方法(调用free
,Dispose
或删除对实例的所有引用)从外部解决。
我的想法是我创建了一个实例,在构造函数中,我启动了私有计时器。当计时器结束时,它将调用一些实例方法并销毁变量。
我认为在C#中,当Dispose
被实现时,应该可以在自己上调用IDisposable
,但这不会破坏实例。
在C ++中,我可以调用destructor
,但这会导致内存泄漏,而且这是非常糟糕的做法。
在Java中我没有任何线索,分配给this
它是不可能的,因为它是final
字段。
那么有什么方法可以摧毁自己吗?
答案 0 :(得分:9)
您的问题非常有趣,我不知道在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
实例为空,尽管它已在{{1}内创建的构造函数。
答案 1 :(得分:3)
C ++:如果一个对象是动态分配的,它可以在自己的函数中删除它的this指针,只要在该点之后再也不再使用该指针。
答案 2 :(得分:2)
不,没有办法在C#
中实现您想要做的事情。
如果你考虑一个例子:
public class Kamikadze {
......
private void TimerTick(..)
{
....
if(itsTime) {
DestroyMe();
}
}
.....
}
var kamikadze = new Kamikadze ();
稍后会调用<{1}} 清除内部数据。
但是引用DestroyMe()
(指针,如果你愿意的话)仍然有效并指向该内存位置,因此kamikadze
将不会执行任何操作,也不会收集它, GC
的实例将留在记忆中。
答案 3 :(得分:1)
对于C ++,请看一下: http://www.parashift.com/c++-faq/delete-this.html
答案 4 :(得分:1)
我能想到的最接近C#的东西:
在创建时,每个对象都在GC根目录中存储对自身的引用,例如将引用放入类静态列表中。在课堂之外,没有人被允许存储(强)对象的引用。每个人都使用WeakReference
并在触摸对象之前检查Target
是否仍为IsAlive
。这样,保持对象存活的唯一方法就是静态引用。
当对象决定自杀时,它只是从列表中删除引用。 GC迟早会收集对象。或者,如果您真的不耐烦,请拨打GC.Collect()
(哎哟!)。
但我真的会不推荐这个解决方案!
最好在类/对象中添加一些标志来表示它是否仍然存在并让每个人在使用该对象之前检查此标志。这可以与IDisposable
解决方案结合使用。
答案 5 :(得分: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...
答案 6 :(得分: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)
}
}
答案 7 :(得分:0)
我建议使用 NFTLKEY
。您可以从 Nuget package
轻松获取它。最重要的是,它是开源的:github project
比这里的例子更容易理解