Осваиваю С# и вот появилась такая задачка.
Необходимо вывести строчку при входе в метод и при выходе из него.
При этом как можно меньше перегружать тело метода ненужными инструкциями.
В С++ проблем не было (привел пример).
Единственное, что пришло в голову:
void Func()
{
try
{
Console.WriteLine("Enter");
.... (какой-то код с Exceptions - ами и return - ами)
}
finally
{
Console.WriteLine("Leave")
}
}
На С++ делалось проще. А в С# фиг знает когда деструктор вызовется:
class Logger()
{
Logger() {cout << "Enter"}
~Logger() {cout << "Leave"}
}
void Func()
{
Logger log;
.... (какой-то код с Exceptions - ами и return - ами)
}
Здравствуйте, higohertz, Вы писали:
H>На С++ делалось проще. А в С# фиг знает когда деструктор вызовется:
Гм... оригинальный способ... Спасибо за идею!
Аналог на C# (конечно всякие PostSharp и прочие примочки — более профессионально смотрятся, зато ниже просто вариант "перевода" с C++ на C#):
public class Logger : IDisposable
{
public Logger()
{
Console.WriteLine("Начало выполнения...");
}
public void Dispose()
{
Console.WriteLine("Окончание выполнения...");
}
}
void Func()
{
using (Logger log = new Logger())
{
Console.WriteLine("Всякие полезные действия...");
}
}
Красота — наивысшая степень целесообразности. (c) И. Ефремов
Здравствуйте, higohertz, Вы писали:
H>Осваиваю С# и вот появилась такая задачка. H>Необходимо вывести строчку при входе в метод и при выходе из него. H>При этом как можно меньше перегружать тело метода ненужными инструкциями. H>В С++ проблем не было (привел пример).
H>Единственное, что пришло в голову: H>
H>void Func()
H>{
H> try
H> {
H> Console.WriteLine("Enter");
H> .... (какой-то код с Exceptions - ами и return - ами)
H> }
H> finally
H> {
H> Console.WriteLine("Leave")
H> }
H>}
H>
Sinclar (пользуясь случаем, снимаю шляпу еще раз ).
Правда этот вариант ИМХО чуть сложнее, чем предыдущий, но зато тоже красивый!
Схематически можно реализовать примерно так:
// собственно код "библиотеки трассировки":public delegate void EasyMethodHandler();
public static class Tracer
{
public static void Trace(EasyMethodHandler h)
{
Console.WriteLine("Enter");
try
{
h();
}
finally
{
Console.WriteLine("Leave");
}
}
}
// класс, вызовы методов которого будем трассироватьpublic class ClassForeTest
{
public void EasyDoSomething()
{
Console.WriteLine("Вызван метод EasyDoSomething");
}
public void StrParamDoSomething(string str)
{
Console.WriteLine(string.Format("Вызван метод StrParamDoSomething о строковым параметром '{0}'", str));
}
}
// а вот дальше мы собственно пользуемся трассировкой:
...
ClassForeTest obj = new ClassForeTest();
string s = "***any string***";
// можно трассировать вызов каждого метода так:
Tracer.Trace(() => obj.EasyDoSomething());
Tracer.Trace(() => obj.StrParamDoSomething(s));
// или так (то же самое, что две предыдущие строки, только более многословно):
Tracer.Trace(delegate { obj.EasyDoSomething(); });
Tracer.Trace(delegate { obj.StrParamDoSomething(s); });
// а можно трассировать вызов последовательности нескольких методов вот так:
Tracer.Trace(deleagte
{
obj.EasyDoSomething();
obj.StrParamDoSomething(s);
});
...
Красота — наивысшая степень целесообразности. (c) И. Ефремов
Re[3]: Логирование при входе и при выходе из метода
Способ хорош только если всем наплевать оверхеды использования памяти и косвености вызовов. Каждый Trace может вылиться в изготовление двух объектов: делегата и замыкания для него.
/* иЗвиНите зА неРовнЫй поЧерК */
Re[4]: Логирование при входе и при выходе из метода
Здравствуйте, hardcase, Вы писали:
H>Способ хорош только если всем наплевать оверхеды использования памяти и косвености вызовов. Каждый Trace может вылиться в изготовление двух объектов: делегата и замыкания для него.
Ну минусы есть, конечно! Но ведь как красиво!
К тому же применение какого-нибудь PostSharp-а разве будет экономичнее? (я не знаю, я спрашиваю )
Ну а на крайний случай сойдет и первый метод, полученный тупым переводом из C++'ого кода топикстартера (который с реализацией интерфейса IDisposable)
Тут уж, как и всегда при проектировании, надо искать компромисс между красотой и эффективностью.
А хочется И того, И другого — выше уже предлагали Немерле... Тока его же отдельно учить надо, да и не мэйнстрим это пока...
Красота — наивысшая степень целесообразности. (c) И. Ефремов
Re[5]: Логирование при входе и при выходе из метода
Здравствуйте, stomsky, Вы писали:
S>Здравствуйте, hardcase, Вы писали:
H>>Способ хорош только если всем наплевать оверхеды использования памяти и косвености вызовов. Каждый Trace может вылиться в изготовление двух объектов: делегата и замыкания для него. S>Ну минусы есть, конечно! Но ведь как красиво!
С точки зрения C# наверно это красиво. Для меня красиво как-то так:
trace
{
x.Foo();
y.Bar(z);
}
S>К тому же применение какого-нибудь PostSharp-а разве будет экономичнее? (я не знаю, я спрашиваю )
Возможно, я не знаком с полными возможностями кодогенерации в PostSharp, впрочим, идея инструментирования генерированного кода далека от моих представлений о правильном дизайне.
В C# я использовал бы вариант на тему using:
using(new Trace("..."))
{
x.Foo();
y.Bar(z);
}
/* иЗвиНите зА неРовнЫй поЧерК */
Re[6]: Логирование при входе и при выходе из метода
Здравствуйте, higohertz, Вы писали: H>В С++ проблем не было (привел пример).
Ну, если вас устроит решение, максимально близкое к C++, то надо делать вот так:
public class Logger: IDisposable
{
Logger() { Console.WriteLine("Enter"); }
void Dispose() {Console.WriteLine("Leave");}
}
void Func()
{
using(new Logger())
{
.... //(какой-то код с Exceptions - ами и return - ами)
}
}
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Логирование при входе и при выходе из метода
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, higohertz, Вы писали: H>>В С++ проблем не было (привел пример). S>Ну, если вас устроит решение, максимально близкое к C++, то надо делать вот так:
Здравствуйте, hardcase, Вы писали: H>С точки зрения C# наверно это красиво. Для меня красиво как-то так: H>
H>trace
H>{
H> x.Foo();
H> y.Bar(z);
H>}
H>
Хм, мне Ваш вариант тоже более красивым кажется, но я подозреваю, что это уже упоминавшийся выше Немерл, а "trace" в данном примере — это макрос?
А изначально вопрос именно о C# ставился...
H>В C# я использовал бы вариант на тему using: H>
А у этого способа есть другой недостаток: можно "забыть" обернуть создание структуры (согласен, что в данном случае у структуры будут преимущества перед классом) в using. Хотя с точки зрения производительности преимущество.
Ищите компромисс...
Красота — наивысшая степень целесообразности. (c) И. Ефремов
Re[7]: Логирование при входе и при выходе из метода
Здравствуйте, stomsky, Вы писали:
S>Хм, мне Ваш вариант тоже более красивым кажется, но я подозреваю, что это уже упоминавшийся выше Немерл, а "trace" в данном примере — это макрос? S>А изначально вопрос именно о C# ставился...
Да, это макрос. Кажется, в стандартной поставке даже что-то подобное было.
S>А у этого способа есть другой недостаток: можно "забыть" обернуть создание структуры (согласен, что в данном случае у структуры будут преимущества перед классом) в using. Хотя с точки зрения производительности преимущество.
Забыть на самом деле сложно, если знать способ использования логгера. Кроме того в вижаке есть возможность прогнать анализ кода — он выявит места, где программист забыл сказать Dispose.
/* иЗвиНите зА неРовнЫй поЧерК */
Re[3]: Логирование при входе и при выходе из метода