Т.е. хочу дописать к реализуемым интерфейсам IDisposable, да собрать все члены класса, которые реализуют IDsposable.
Приписываю над классом волшебную надпись: [Disposable] — получаю привет от компилятора: «The AddImplementedInterface method can be called only before MacroPhase.BeforeTypedMembers phase.»
То есть, «можешь добавлять интерфейсы только в макросах, срабатывающих на стадии MacroPhase.BeforeTypedMembers», но ведь я и так указал эту стадию? %)
Товарисчи, наставьте на путь истинный пожалуйста.
Re: Вопрос про typeBuilder.AddImplementedInterface
От:
Аноним
Дата:
26.08.11 12:13
Оценка:
Прошу прощения. Разобрался.
Re: Вопрос про typeBuilder.AddImplementedInterface
Здравствуйте, Аноним, Вы писали: А>Т.е. хочу дописать к реализуемым интерфейсам IDisposable, да собрать все члены класса, которые реализуют IDsposable. А>Приписываю над классом волшебную надпись: [Disposable] — получаю привет от компилятора: «The AddImplementedInterface method can be called only before MacroPhase.BeforeTypedMembers phase.» А>То есть, «можешь добавлять интерфейсы только в макросах, срабатывающих на стадии MacroPhase.BeforeTypedMembers», но ведь я и так указал эту стадию? %)
Скажу больше. Реально проблем можно избежать только если использовать фазу MacroPhase.BeforeInheritance, так как именно после нее компилятор производит проверки связанные с наследованием и реализацией интерфейсов.
Но делу это никак не помешает. Дело в том, что макрос может работать на разных стадиях. На стадии MacroPhase.BeforeInheritance добавляешь, с помощью AddImplementedInterface, интерфейс и метод Dispose, а на стадии MacroPhase.WithTypedMembers собираешь нужную для реализации метода Dispose информацию и генерируешь его тело.
В твоем же случае имеет смысл вообще завести два макроса. Один будет работать на фазе MacroPhase.BeforeInheritance и только лишь добавлять реализацию IDisposable, а второй будет вешаться на добавляемый метод Dispose и будет генерировать его тело. Это позволит не искать Dispose. Второй макрос, естественно, должен работать на стадии MacroPhase.WithTypedMembers и иметь MacroTargets.Method.
Кроме того ты совершенно не верно пытаешься получить информацию о членах реализующих IDisposable.
Ниже приведен пример реализации таких макросов.
Disposable.n — реализация макроса применяемого к классу (типу).
Скрытый текст
using Nemerle;
using Nemerle.Compiler;
using Nemerle.Compiler.Parsetree;
namespace MacroTestLib
{
// Выполняется на фазе BeforeInheritance, так как этот макрос должен изменять список
// реализованных интерфейсов.
[MacroUsage(MacroPhase.BeforeInheritance, MacroTargets.Class)]
macro Disposable(typeBuilder : TypeBuilder)
{
// Добавляем "наследование" IDisposable.
typeBuilder.AddImplementedInterface(<[ System.IDisposable ]>);
// Добавляем метод Dispose. Метод помечаем макроатрибутом ImplementDispose.
// Он "вызовится" позже.
typeBuilder.Define(<[ decl: [MacroTestLib.ImplementDispose] public Dispose() : void { } ]>);
}
}
ImplementDispose.n -реализация макроса применяемого к методу Dispose.
Скрытый текст
using Nemerle;
using Nemerle.Collections;
using Nemerle.Compiler;
using Nemerle.Compiler.Parsetree;
using Nemerle.Compiler.Typedtree;
using Nemerle.Text;
using Nemerle.Utility;
using System;
using System.Collections.Generic;
using System.Linq;
namespace MacroTestLib
{
// Макрос работает на фазе WithTypedMembers, так как ему нужна информация о типх членов.
/// Данный макрос должен применяться к методу Dispose!
[MacroUsage(MacroPhase.WithTypedMembers, MacroTargets.Method)]
macro ImplementDispose(typeBuilder : TypeBuilder, method : MethodBuilder)
{
ImplementDisposeImpl.DoTransform(Macros.ImplicitCTX(), typeBuilder, method)
}
module ImplementDisposeImpl
{
public DoTransform(typer : Typer, typeBuilder : TypeBuilder, method : MethodBuilder) : void
{
Macros.DefineCTX(typer); // это нружно для цитаты <[ ttype: System.IDisposable ]>
// assert2(false);
// Так надо получать описание типа в макросах. Использовать System.Type в макросах нельзя!def iDisposableType = <[ ttype: System.IDisposable ]>;
def isMemberTypeImplementIDisposable(member : IMember) : bool
{
// Вызвать Dispose() имеет смысл только у полей и свойств определенных в текущем классе. Фильтрум их...
(member is IProperty || member is IField)
// Получаем тип члена и проверям, что он унифицируется с IDisposable. А использовать System.Type в макросах нельзя!
&& member.GetMemType().TryRequire(iDisposableType)
}
// Получаем все экземплярные поля и свойства типы которых реализуют IDisposable.def members = typeBuilder.GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Instance
| BindingFlags.Public | BindingFlags.NonPublic)
.Filter(isMemberTypeImplementIDisposable);
// Преобразуем список членов в список выражений проиводящий обращение к ним и вызвающих от них Dispose().
// Оператор ?. позволяет защититься от вызова по нулевому указателю.def exprs = members.Map(m => <[ (this.$(m.Name : usesite) : System.IDisposable)?.Dispose() ]>);
// Заменяем тело Dispose-а данного класа. Цитата ..$х раскрывает список выражений.method.Body = <[ { ..$exprs } ]>;
}
}
}
Test.n — тестовое приложение использующее макрос.
Скрытый текст
using System.Console;
using System.IO;
using MacroTestLib;
[Record]
[Disposable]
class Test
{
private FileStream : FileStream;
private Str : string;
private Reader : TextReader;
}
module Program2
{
Main() : void
{
def x = Test(null, "", null);
x.Dispose();
}
}
Код метода Dispose полученный с помощью декомпиляции в C#.
Скрытый текст
public void Dispose()
{
IDisposable fileStream = this.FileStream;
if (fileStream != null)
{
fileStream.Dispose();
}
IDisposable reader = this.Reader;
if (reader != null)
{
reader.Dispose();
}
}
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Вопрос про typeBuilder.AddImplementedInterface
От:
Аноним
Дата:
27.08.11 03:02
Оценка:
ёмаё, Влад, ЧЕЛОВЕЧИЩЕ, спасибо тебе большое!
Re[2]: Вопрос про typeBuilder.AddImplementedInterface
От:
Аноним
Дата:
27.08.11 17:39
Оценка:
VladD2, можно вопрос про System.Type?
Почему нельзя его в паттерн матчинге проверять?
В таком ключе:
match(typeof(obj))
{
| typeof(IDisposable) =>
}
?
Re[3]: Вопрос про typeBuilder.AddImplementedInterface
Потому что справа от знака => в match можно использовать только константы (даже не константы — литералы). Хотя typeof(IDisposable) — к сожалению, не литерал. Но зачем писать так? Можно по-другому:
match (obj)
{
| disp is IDisposable =>
{
// здесь disp — это obj, приведенный к IDisposable
}
| _ => ...
}
Re[4]: Вопрос про typeBuilder.AddImplementedInterface
Здравствуйте, catbert, Вы писали:
C> Хотя typeof(IDisposable) — к сожалению, не литерал.
* вместо "хотя" там "а"
Re[4]: Вопрос про typeBuilder.AddImplementedInterface
От:
Аноним
Дата:
27.08.11 19:05
Оценка:
catbert, спасибо большое за разъяснения!
C>Потому что справа от знака => в match можно использовать только константы (даже не константы — литералы).
наверное, все-таки «слева от знака».
Re[3]: Вопрос про typeBuilder.AddImplementedInterface
Здравствуйте, Аноним, Вы писали:
А>Почему нельзя его в паттерн матчинге проверять?
Его вообще нельзя использовать в макросах. System.Type доступен только в рантайме. Во время компиляции типов определенных в проектах может просто не быть.
Кроме того компилятор (а значит и макросы) могут быть собраны для платформы отличной от той для которой будет собираться приложение.
Ну, код вроде:
superType.GetType()
возвратит тип объекта на который указывает superType, т.е. что-то вроде FixedType или TypeVar.
А они тебе точно не нужны, да и IDisposable не реализуют — 100%.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Вопрос про typeBuilder.AddImplementedInterface
От:
Аноним
Дата:
28.08.11 11:39
Оценка:
hardcase, спасибо!
Re[4]: Вопрос про typeBuilder.AddImplementedInterface
От:
Аноним
Дата:
28.08.11 11:48
Оценка:
VladD2, в который раз благодарю за разъяснения!
Re[2]: Вопрос про typeBuilder.AddImplementedInterface
От:
Аноним
Дата:
02.09.11 21:53
Оценка:
Здравствуйте, VladD2.
Пытаюсь изучать Nemerle. Попробовал скомпилить этот пример. Ругается на