Я читал некоторые статьи о кешировании и запоминании и о том, как легко реализовать его с помощью делегатов и дженериков. Синтаксис был довольно простым, и его удивительно легко реализовать, но я просто чувствую, что из-за повторяющегося характера он должен быть способен генерировать код на основе атрибута, вместо того, чтобы писать один и тот же файл сантехники снова и снова.
Скажем, мы начинаем с примера по умолчанию:
class Foo
{
public int Fibonacci(int n)
{
return n > 1 ? Fibonacci(n-1) + Fibonacci(n-2) : n;
}
}
И затем запомните это:
// Let 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;
}
}
Честно говоря, я знаю, что это больше похоже на саму компилятор, который должен быть преобразован препроцессором, чем фактическое генерирование кода, но мой вопрос:
- Как вы думаете, лучший способ найти методы в исходном файле С#, которые имеют данный атрибут, разбор типов параметров и возвращаемого типа и создание делегата, который соответствует этому отпечатку пальца.
- Что было бы лучшим способом интегрировать это в процесс сборки, не перезаписывая мой код. Возможно ли выполнить предварительную обработку исходных файлов, прежде чем передавать их компилятору?
Спасибо за любые идеи.
Обновление
Я заглянул в библиотеку Postsharp, как предположил Шей, и это казалось очень подходящим для работы в некритических приложениях, таких как управление транзакциями, трассировка и безопасность.
Однако при использовании его в критическом по времени контексте он оказался намного медленнее, чем делегат. Один миллион итераций примера Fibonacci с каждой реализацией привел к более медленному времени выполнения на 80x. (0,012 мс postsharp против 0,00015ms делегата за звонок)
Но, честно говоря, результат вполне приемлем в контексте, в котором я намерен его использовать. Спасибо за ответы!
Update2
Видимо автор PostSharp упорно работает над версии 2.0, который будет включать в себя, помимо всего прочего, повышение производительности в произведенного кода и компиляции время.