Итак, задача — система, позволяющая создавать пользовательские функции для SQL-БД. Функции пишутся на дотнете. Функции бывают двух видов — скалярные и агрегаты. Допускается перегрузка функций. Агрегаты фактически представляют собой две функции — одна вызывается по ходу вычислений, а другая только один раз, в конца (таков дизайн БД, я тут не причем).
Пока останавливаюсь на таком:
1. Для создания собственной функции необходимо реализовать интерфейс IFunction. На настоящий момент интерфейс получает универсальным — и для скалярных, и для агрегатов:
public interface IFunction
{
void Execute(CallType call, IFunctionContext context);
}
CallType — энумерация, которая показывает, в каком качестве вызывается функция:
public enum CallType
{
Normal,
Step,
Final
}
С одной стороны вроде и неплохо. С другой — как-то не очень. Во-первых, единственный смысл этой функции отличить вызов "обычной" скалярной функции от одного из вызовов в цепочке агрегата. Далее — единственный интерфейс для функций, принцип работы которых сильно отличается тоже не очень.
Логически высматривается такая картинка:
IFunction -> IScalarFunction
-> IAggregateFunction
И регистрация функций будет выглядеть красиво. Но, во-первых, IFunction получается пустым. Ну просто нечего туда засунуть. И как-то некрасиво это. Во-вторых интерфейсы тоже выглядят довольно странно:
public interface IScalarFunction : IFunction
{
void Execute(IFunctionContext context);
}
public interface IAggregateFunction : IFunction
{
void Execute(CallType call, IFunctionContext context);
}
Не знаю, может, это только я, но как-то глаз колит.
2. Далее. Как вы заметили, есть такая штука как IFunctionContext. Причем очень даже важная штука, вот как она выглядит:
public interface IFunctionContext
{
Variant GetParameter(int index);
void SetResultValue<T>(T value) where T : IConvertible;
void SetResultBlob(byte[] buffer);
void SetResultNull();
void SetResultZeroBlob(int length);
void ReportError(FunctionError error);
void ReportError(int code, string message);
}
Изящно, не правда ли?
Предназначение этого интерфейса, думаю, вполне понятно по объявлению, но уже как-то он "смешивает напитки". Хотелось бы как-то это поменять...
Заранее оговорюсь, что регистрацию через лямбду я не рассматриваю, т.к. на мой взгляд это весьма частный случай и далеко не весь код будет выглядеть понятно и красиво при передаче лямбды. Поэтому мне кажется, что регистрация через лямбду должна быть реализована как "фишка" поверх описываемой здесь инфраструктуры.
Пока все. Буду рад любым советам.