Я читал несколько статей о кэшировании и запоминании и о том, как легко реализовать его с помощью делегатов и обобщений. Синтаксис был довольно простым, и его удивительно легко реализовать, но я просто чувствую, что из-за повторяющейся природы должна быть возможность генерировать код на основе атрибута вместо того, чтобы писать один и тот же программный код снова и снова.
Допустим, мы начнем с примера по умолчанию:
class Foo
{
public int Fibonacci(int n)
{
return n > 1 ? Fibonacci(n-1) + Fibonacci(n-2) : n;
}
}
А потом запомнить это:
// Let's say we have a utility class somewhere with the following extension method:
// public static Func<TResult> Memoize<TResult>(this Func<TResult> f)
class Foo
{
public Func<int,int> Fibonacci = fib;
public Foo()
{
Fibonacci = Fibonacci.Memoize();
}
public int fib(int n)
{
return n > 1 ? Fibonacci(n-1) + Fibonacci(n-2) : n;
}
}
Я подумал, не будет ли проще просто создать генератор кода, который выплевывает этот код, как только он найдет метод с тегами, который соответствует одному из методов расширения Memoize. Поэтому вместо написания этого сантехнического кода я мог бы просто добавить атрибут:
class Foo
{
[Memoize]
public int Fibonacci(int n)
{
return n > 1 ? Fibonacci(n-1) + Fibonacci(n-2) : n;
}
}
Честно говоря, я знаю, что это больше похоже на сахар компилятора, который должен быть преобразован препроцессором, чем фактическая генерация кода, но мой вопрос:
- Как вы думаете, что является лучшим способом найти методы в исходном файле c #, которые имеют заданный атрибут, проанализировать типы параметров и тип возвращаемых данных и сгенерировать делегат, который соответствует этому отпечатку
- Что было бы лучшим способом интегрировать это в процесс сборки, не переписывая мой код? Можно ли выполнить некоторую предварительную обработку исходных файлов перед передачей их компилятору?
Спасибо за любые идеи.
Обновление
Я заглянул в библиотеку Postsharp, как и предлагал Шей, и она казалась очень подходящей для работы в не критичных ко времени приложениях, таких как Transaction Management, Tracing или Security.
Однако при использовании его в условиях, критичных ко времени, он оказался намного медленнее, чем делегат. Один миллион итераций примера Фибоначчи с каждой реализацией привел к снижению производительности в 80 раз. (0,012 мс после звонка против 0,00015 мс на одного звонка)
Но, честно говоря, результат вполне приемлем в контексте, в котором я намерен его использовать. Спасибо за ответы!
Update2
Очевидно, автор Postsharp усердно работает над выпуском 2.0 , который будет включать, помимо прочего, повышение производительности производимого кода и время компиляции.