Реализовал сабж.
Пример использования:
disposable class BaseClass
{
dispose Dispose() : void
{
WriteLine("cleaning up BaseClass");
}
}
class DerivedClass : BaseClass
{
[Dispose]
Dispose1() : void
{
WriteLine("cleaning up DerivedClass");
}
// [Dispose] //Error: Dispose method already defined
// Dispose2() : void
// {
// }
}
Main() : void
{
def test=DerivedClass();
dispose test;
_=ReadLine();
}
Выведет:
cleaning up DerivedClass
cleaning up BaseClass
Код макросов:
[Nemerle.MacroUsage(MacroPhase.BeforeInheritance, MacroTargets.Class)]
macro Disposable (tb : TypeBuilder)
syntax("disposable")
{
tb.AddImplementedInterface(
<[ System.IDisposable ]>
);
}
[Nemerle.MacroUsage(MacroPhase.BeforeTypedMembers, MacroTargets.Method)]
macro Dispose (tb : TypeBuilder, mb : ParsedMethod)
syntax ("dispose")
{
def checkAlreadyDefined()
{
foreach (ClassMember.Function (_, _, _) as f in tb.GetParsedMembers (true))
when(f.Name=="Dispose" && f.Attributes & NemerleAttributes.SpecialName != 0)
Message.FatalError("Dispose method already defined");
}
def checkImplements(t : TypeInfo) : bool
{
| tc is TypeBuilder =>
if(List.ForAll(tc.GetParsedMembers(true), x=>{
!(x is ClassMember.Function && x.Name == "_N_dispose");
}))
checkImplements(t.BaseType)
else
true
| _ => false;
}
checkAlreadyDefined();
def attrs=Modifiers(NemerleAttributes.SpecialName | NemerleAttributes.Protected, []);
if (!checkImplements(tb))
{
tb.Define(
<[
decl: _N_dispose() : void implements System.IDisposable.Dispose
{
this.Dispose(true);
System.GC.SuppressFinalize(this);
}
]>);
attrs.mods |= NemerleAttributes.Virtual;
tb.Define(
<[
decl: ..$attrs Dispose(IsDisposing : bool) : void
{
if(IsDisposing)
$(mb.Name : dyn) ();
else
Finalize();
}
]>);
tb.Define(
<[
decl: protected override Finalize() : void
{
this.Dispose(false);
}
]>);
}
else
{
attrs.mods |= NemerleAttributes.Override;
tb.Define(
<[
decl: ..$attrs Dispose(IsDisposing : bool) : void
{
if (IsDisposing)
{
try
{
$(mb.Name : dyn) ();
}
finally
{
base.Dispose(true);
}
}
else
{
base.Dispose(false);
}
}
]>);
}
}
macro DisposeOperator(expr)
syntax ("dispose", expr)
{
<[
maybe_valuetype_dispose($expr);
]>;
}
Есть пара нюансов:
1. Пришлось сделать дополнительный макрос Disposable, который тупо добавляет интерфейс IDisposable. Хотел сделать одним макросом, но наследоваться можно только в режиме MacroPhase.BeforeInheritance, а получать информацию о методах базовых классов — не ранее, чем в режиме MacroPhase.BeforeTypedMembers.
2. Хотел добавить синтаксический сахар и писать методы Dispose в виде ~this() { } — не вышло.
3. Оператор dispose выполняет проверку на null и уже тогда вызывает метод Dispose().
В человечишке все должно быть прекрасненьким: и одёжка, и душенка, и мордочка, и мыслишки.
Здравствуйте, BOleg, Вы писали:
BO>Реализовал сабж.
Тогда, может, еще и проверку на то, что Dispose уже вызван в каждый метод/свойство добавить? Руками-то этот код писать никто никогда не будет
Здравствуйте, mrozov, Вы писали:
M>Тогда, может, еще и проверку на то, что Dispose уже вызван в каждый метод/свойство добавить? Руками-то этот код писать никто никогда не будет
Можно будет и добавить (опционально ессно). Сейчас реализовал только нужную мне часть.
В человечишке все должно быть прекрасненьким: и одёжка, и душенка, и мордочка, и мыслишки.