То есть деструктор должен вызвать предудыщие переопределения метода object.Finalize() после своего тела.
Так вот, разработчики компилятора C# при генерации данного кода видимо тупо искали а базовых классах виртуальный метод по имени "Finalize" и генерировали для него base-вызов (который в C# всегда невиртуальный), так что если создать абстрактный метод (или виртуальный, но не override!) с таким именем, то компилятор C# успешно генерирует невиртуальный вызов абстрактного метода:
Microsoft (R) .NET Framework PE Verifier. Version 4.0.30319.1
Copyright (c) Microsoft Corporation. All rights reserved.
[IL]: Error: [ConsoleApplication1.exe : Goodbye::Finalize][offset 0x00000010] Call not allowed on abstract methods.
1 Error(s) Verifying bin\Debug\ConsoleApplication1.exe
А в рантайме вызов финализера, видимо, просто молча валится на этапе JIT'а...
Здравствуйте, _FRED_, Вы писали:
_FR>Здравствуйте, Mab, Вы писали:
Mab>>Как устроен DontSayGoodbye?
_FR>И мои пять копеек:
А вот так точно никогда не вызывает финализер
using System;
using System.Runtime.Remoting.Activation;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;
[DontSayGoodbye]
class DontSayGoodbye : ContextBoundObject
{
sealed class DontSayGoodbyeRealProxy : RealProxy
{
public DontSayGoodbyeRealProxy(Type type) : base(type) { }
public override IMessage Invoke(IMessage msg)
{
var ctorMsg = msg as IConstructionCallMessage;
if (ctorMsg == null) throw new NotSupportedException();
var o = InitializeServerObject(ctorMsg);
GC.SuppressFinalize(GetUnwrappedServer());
return o;
}
}
sealed class DontSayGoodbyeAttribute : ProxyAttribute
{
public override MarshalByRefObject CreateInstance(Type type)
{
return (MarshalByRefObject) new DontSayGoodbyeRealProxy(type).GetTransparentProxy();
}
}
}
Здравствуйте, Константин Л., Вы писали:
КЛ>из-за protected? каков механизм?
Противоречащий C# Language Specification Version 4.0
10.13 Destructors
... Destructors are implemented by overriding the virtual method Finalize on System.Object. C# programs are not permitted to override this method or call it (or overrides of it) directly. For instance, the program
class A
{
override protected void Finalize() {} // error
public void F() {
this.Finalize(); // error
}
}
contains two errors. The compiler behaves as if this method, and overrides of it, do not exist at all. Thus, this program:
class A
{
void Finalize() {} // permitted
}
is valid, and the method shown hides System.Object’s Finalize method.
П>А в рантайме вызов финализера, видимо, просто молча валится на этапе JIT'а...
Не думаю, что дело в неверифицируемости этого кода. Все остается в силе, даже если написать
class DontSayGoodbye
{
protected virtual void Finalize() {}
}
Дело в другом. Объявляя в DontSayGoodbye вирутальный метод с именем Finalize мы заодно скрываем базовый object.Finalize. Убедиться в этом легко, запустив ildasm -- у метода будет стоять флаг newslot. (Кстати, компилятор обычного в таких случаях предупреждения не выдаст, а явно поставленный модификатор new сочтет избыточным.)
Соответственно, переопределение Finalize, которое породит компилятор для Goodbye, будет перекрывать (override) имеенно DontSayGoodbye.Finalzie, а не object.Finalize. Вызов же финализатора, конечно, делается через токен object.Finalize (как самый обычный вирутальный вызов), так что сработает object.Finalize, который пуст.
Итого, после того, как в базовом классе Finalize был скрыт, никаких шансов у производного его переопределить не осталось.