Ответ 1
Я сталкиваюсь с этим атрибутом memoizer с использованием postsharp
Я читал некоторые статьи о кешировании и запоминании и о том, как легко реализовать его с помощью делегатов и дженериков. Синтаксис был довольно простым, и его удивительно легко реализовать, но я просто чувствую, что из-за повторяющегося характера он должен быть способен генерировать код на основе атрибута, вместо того, чтобы писать один и тот же файл сантехники снова и снова.
Скажем, мы начинаем с примера по умолчанию:
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, который будет включать в себя, помимо всего прочего, повышение производительности в произведенного кода и компиляции время.
Я сталкиваюсь с этим атрибутом memoizer с использованием postsharp
Я использовал следующую функцию Memoize в моем проекте:
public class Foo
{
public int Fibonacci(int n)
{
return n > 1 ? Fibonacci(n - 1) + Fibonacci(n - 2) : n;
}
}
class Program
{
public static Func<Т, TResult> Memoize<Т, TResult>(Func<Т, TResult> f) where Т : IEquatable<Т>
{
Dictionary<Т, TResult> map = new Dictionary<Т, TResult>();
return a =>
{
TResult local;
if (!TryGetValue<Т, TResult>(map, a, out local))
{
local = f(a);
map.Add(a, local);
}
return local;
};
}
private static bool TryGetValue<Т, TResult>(Dictionary<Т, TResult> map, Т key, out TResult value) where Т : IEquatable<Т>
{
EqualityComparer<Т> comparer = EqualityComparer<Т>.Default;
foreach (KeyValuePair<Т, TResult> pair in map)
{
if (comparer.Equals(pair.Key, key))
{
value = pair.Value;
return true;
}
}
value = default(TResult);
return false;
}
static void Main(string[] args)
{
var foo = new Foo();
// Transform the original function and render it with memory
var memoizedFibonacci = Memoize<int, int>(foo.Fibonacci);
// memoizedFibonacci is a transformation of the original function that can be used from now on:
// Note that only the first call will hit the original function
Console.WriteLine(memoizedFibonacci(3));
Console.WriteLine(memoizedFibonacci(3));
Console.WriteLine(memoizedFibonacci(3));
Console.WriteLine(memoizedFibonacci(3));
}
}
В моем проекте мне нужны были только функции с одним аргументом, которые реализуют IEquatable < Т > , но это может быть еще более обобщено. Еще одно важное замечание состоит в том, что этот код не является потокобезопасным. Если вам нужна безопасность потоков, вам нужно будет синхронизировать доступ чтения/записи к хэш-таблице внутренней карты.
Чтобы конкретно указать свои баллы:
Если вы пишете плагин PostSharp вместо использования его библиотеки LAOS, вы не получите никакого удара по производительности.