Дизайн интерфейса
От: Воронков Василий Россия  
Дата: 12.06.09 12:02
Оценка:
Итак, задача — система, позволяющая создавать пользовательские функции для 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);
}


Изящно, не правда ли? Предназначение этого интерфейса, думаю, вполне понятно по объявлению, но уже как-то он "смешивает напитки". Хотелось бы как-то это поменять...

Заранее оговорюсь, что регистрацию через лямбду я не рассматриваю, т.к. на мой взгляд это весьма частный случай и далеко не весь код будет выглядеть понятно и красиво при передаче лямбды. Поэтому мне кажется, что регистрация через лямбду должна быть реализована как "фишка" поверх описываемой здесь инфраструктуры.

Пока все. Буду рад любым советам.
Re: Дизайн интерфейса
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 12.06.09 14:42
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Пока все. Буду рад любым советам.


А чем не подхоит способ как в SQL CLR?
Re[2]: Дизайн интерфейса
От: Воронков Василий Россия  
Дата: 12.06.09 14:56
Оценка:
Здравствуйте, gandjustas, Вы писали:

ВВ>>Пока все. Буду рад любым советам.

G>А чем не подхоит способ как в SQL CLR?

Это такой:

class SomeClass
{
  [SqlFunction]
  int Abs(int val)
  {
     return Math.Abs(val);
  }
}


?
Такой вариант имеется в виду, но есть ряд нюансов.
Основная проблема — чтобы обеспечить вызов такой функции и не получить при этом мега-тормоза, придется джитить код. И потом не очень ясно, как быть с агрегатами.

Наконец, а насколько это удобно? Т.е. implementation cost — немалький. А кардинальный отличий от своего варианта я не вижу. Кардинально удобнее для вышеозначенного примера было бы сделать:

RegisterFunction("Abs", i => Math.Abs(i));


А если код ф-ции большой и сложный, то не по фигу — интерфейс ли реализовать или атрибутом ее пометить? Лучше уж я код поджитю, чтобы осущетсвить поддержку лямб как в примере выше — уже поверх всех своих интерфейсов.
Или нет?
Re[3]: Дизайн интерфейса
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 13.06.09 07:49
Оценка: 7 (1)
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, gandjustas, Вы писали:


ВВ>>>Пока все. Буду рад любым советам.

G>>А чем не подхоит способ как в SQL CLR?

ВВ>Это такой:


ВВ>
ВВ>class SomeClass
ВВ>{
ВВ>  [SqlFunction]
ВВ>  int Abs(int val)
ВВ>  {
ВВ>     return Math.Abs(val);
ВВ>  }
ВВ>}
ВВ>


Примерно так.


ВВ>Такой вариант имеется в виду, но есть ряд нюансов.

ВВ>Основная проблема — чтобы обеспечить вызов такой функции и не получить при этом мега-тормоза, придется джитить код.
Я думаю динамической кодогенерацией рано или поздно придется заниматься в целях быстройдействия. На первых порах можно огранииться делегатами.

ВВ>И потом не очень ясно, как быть с агрегатами.

Также как в SQL CLR.

ВВ>Наконец, а насколько это удобно? Т.е. implementation cost — немалький. А кардинальный отличий от своего варианта я не вижу.

А чем implementation cost немаленький. Вместо ссылки на интерфейс держать ссылку на делегат.

ВВ>Кардинально удобнее для вышеозначенного примера было бы сделать:

ВВ>
ВВ>RegisterFunction("Abs", i => Math.Abs(i));
ВВ>

Такой вариант имхо тоже стоит поддерживать, более того вариант с атрибутом можно сделать через такую функцию.
Я для таких целей предпочитаю делать сначала императивный API, потом на его базе достраивать декларативный на атрибутах или с внешним конфигом.

ВВ>А если код ф-ции большой и сложный, то не по фигу — интерфейс ли реализовать или атрибутом ее пометить? Лучше уж я код поджитю, чтобы осущетсвить поддержку лямб как в примере выше — уже поверх всех своих интерфейсов.

ВВ>Или нет?
1)Пустой (маркерный) интерфейс семантически эквивалентен атрибуту
2)Атрибут позволяет передать больше информации
3)Использование интерфейсов приводит к использованию экземпляров объектов, что создает вопросы о времени жизни и конкурентном доступе к данным, статические функции выгоднее в этом плане
4)С помощью статических функций можно обеспечить работу Linq-провайдера с этими же функциями.
Re[4]: Дизайн интерфейса
От: Воронков Василий Россия  
Дата: 13.06.09 08:21
Оценка:
Здравствуйте, gandjustas, Вы писали:

ВВ>>Такой вариант имеется в виду, но есть ряд нюансов.

ВВ>>Основная проблема — чтобы обеспечить вызов такой функции и не получить при этом мега-тормоза, придется джитить код.
G>Я думаю динамической кодогенерацией рано или поздно придется заниматься в целях быстройдействия. На первых порах можно огранииться делегатами.

Делегаты я не понял как помогут. См. ниже.

ВВ>>И потом не очень ясно, как быть с агрегатами.

G>Также как в SQL CLR.

Ну здесь бек-энд немного другой. Я говорил — изначально для агрегата предполагаются две ф-ции — Step и Final. Вполне можно сделать и так, что агрегат будет одной функцией, имеющей состояние — и передавать это состояние каким-либо способом. Можно просто сообщать с помощью флажка о том, что происходит "последний" вызов (правда, при этом аргументов не будет). Можно сделать две функции как в самой базе.

ВВ>>Наконец, а насколько это удобно? Т.е. implementation cost — немалький. А кардинальный отличий от своего варианта я не вижу.

G>А чем implementation cost немаленький. Вместо ссылки на интерфейс держать ссылку на делегат.

А откуда у меня делегат-то возьмется? У меня ж произвольная сигнатура метода. Его тупо через рефлекшин придется дергать. Да и в любом случае — даже если изловчиться как-то прикрутить сюда делегат — его придется вызывать через Invoke — и по сути хрен редьки не слаще. Потом очевидно же подобное решение с т.з. производительности неприемлимо совершенно. С интерфейсами — еще более или менее. По крайней мере можно первую версию выкатить, которая "терпит" interface call footprint. (Например, на древнем Целероне 2400 я разницу между прямым вызовом и интерфейсом вижу где-то на миллионе итераций, а рефлекшин сразу по глазам бьет).

ВВ>>Кардинально удобнее для вышеозначенного примера было бы сделать:

ВВ>>
ВВ>>RegisterFunction("Abs", i => Math.Abs(i));
ВВ>>

G>Такой вариант имхо тоже стоит поддерживать, более того вариант с атрибутом можно сделать через такую функцию.
G>Я для таких целей предпочитаю делать сначала императивный API, потом на его базе достраивать декларативный на атрибутах или с внешним конфигом.

Вот, собственно, об этом и речь. Императивное АПИ — это ведь не всякие там штучки с атрибутами. Собственно, что атрибут, что лямбда — это примочки для регистрации функции. Моя мысль — сделать изначально некоторую модель, поверх которой уже накручивать всю красоту. И тогда мы возвращаемся к изначальному вопросу.

ВВ>>А если код ф-ции большой и сложный, то не по фигу — интерфейс ли реализовать или атрибутом ее пометить? Лучше уж я код поджитю, чтобы осущетсвить поддержку лямб как в примере выше — уже поверх всех своих интерфейсов.

ВВ>>Или нет?
G>1)Пустой (маркерный) интерфейс семантически эквивалентен атрибуту

Я и не хочу пустой интерфейс.

G>2)Атрибут позволяет передать больше информации


Как видно из моих примеров — вся информация сводится к: имя, кол-во параметров, тип ф-ции. Все.

G>3)Использование интерфейсов приводит к использованию экземпляров объектов, что создает вопросы о времени жизни и конкурентном доступе к данным, статические функции выгоднее в этом плане

G>4)С помощью статических функций можно обеспечить работу Linq-провайдера с этими же функциями.

А причем тут интерфейсы, статические функции? Это, мне кажется, клиентский код должен решать что и как ему удобнее. Интерфейсы тоже не обязывают к созданию экземпляров — можно сделать синглтон.
Потом я не понял — что все-таки ты предлагаешь? Сам же говоришь: "Я для таких целей предпочитаю делать сначала императивный API". Как будет выглядеть этот императивный API?
Re[5]: Дизайн интерфейса
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 13.06.09 10:31
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>>>И потом не очень ясно, как быть с агрегатами.

G>>Также как в SQL CLR.

ВВ>Ну здесь бек-энд немного другой. Я говорил — изначально для агрегата предполагаются две ф-ции — Step и Final. Вполне можно сделать и так, что агрегат будет одной функцией, имеющей состояние — и передавать это состояние каким-либо способом. Можно просто сообщать с помощью флажка о том, что происходит "последний" вызов (правда, при этом аргументов не будет). Можно сделать две функции как в самой базе.


Да посмотри уже как это в SQL CLR делается.

ВВ>>>Наконец, а насколько это удобно? Т.е. implementation cost — немалький. А кардинальный отличий от своего варианта я не вижу.

G>>А чем implementation cost немаленький. Вместо ссылки на интерфейс держать ссылку на делегат.
ВВ>А откуда у меня делегат-то возьмется?
Delegate.CreateDelegate

ВВ>У меня ж произвольная сигнатура метода.

Не совсем, должны быть какие-то соглашения о параметрах метода, вполне возможно что будет именно фиксированная сигнатура.

ВВ>Его тупо через рефлекшин придется дергать.

Delegate.DynamicInvoke или писать (взять из интернета) обертку для типизированных вызовов с помощью DynamicMethod.

ВВ>Да и в любом случае — даже если изловчиться как-то прикрутить сюда делегат — его придется вызывать через Invoke — и по сути хрен редьки не слаще.

IFunction и IFunctionContext фактически моделируют тоже поведение делегата.
только писать функции немного сложнее будет так как вся "грязная" работа по приведению типов ложится на сам метод.

ВВ>Потом очевидно же подобное решение с т.з. производительности неприемлимо совершенно. С интерфейсами — еще более или менее.

А замеры проводились?
Все равно вы придете к динамической кодогенерации, а там уже IFunctionContext станет излишним.

ВВ>А причем тут интерфейсы, статические функции? Это, мне кажется, клиентский код должен решать что и как ему удобнее. Интерфейсы тоже не обязывают к созданию экземпляров — можно сделать синглтон.

ВВ>Потом я не понял — что все-таки ты предлагаешь? Сам же говоришь: "Я для таких целей предпочитаю делать сначала императивный API". Как будет выглядеть этот императивный API?
так и будет:
RegisterFunction(MethodInfo, other params)
RegisterAggregate(Type,other params) или RegisterAggregate(MethodInfo acc, MethodInfo merge, other params)
Re[6]: Дизайн интерфейса
От: Воронков Василий Россия  
Дата: 13.06.09 13:58
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Да посмотри уже как это в SQL CLR делается.


Я повторюсь — у меня не SQL Server. И способ исполнения агрегата отличается.

ВВ>>У меня ж произвольная сигнатура метода.

G>Не совсем, должны быть какие-то соглашения о параметрах метода, вполне возможно что будет именно фиксированная сигнатура.

Что значит фиксированная сигнатура? На хрена тогда все это нужно? Фиксированная сигнатура это:

MyFunc(params object[] args);


и даже никаких делегатов не надо.
Смысл того "как это в SQL CLR делается" именно в том, что сигнатура произвольная + строгая типизация.

ВВ>>Потом очевидно же подобное решение с т.з. производительности неприемлимо совершенно. С интерфейсами — еще более или менее.

G>А замеры проводились?

Я мерил. Накладные расходы на интерфейс не очень сильные и начинают становиться заметны, когда вызовов *очень* много. А если в запросе будет происходить скан миллиона записей, думаю миллион вызовов через интерфейс покажется назметными с т.з. стоимости.
В любом случае заниматься подобной оптимизацией с самого начала мне кажется избыточным.

G>Все равно вы придете к динамической кодогенерации, а там уже IFunctionContext станет излишним.


Ну вот в SQL CLR он совсем нелишний, кстати.

G>так и будет:

G>RegisterFunction(MethodInfo, other params)
G>RegisterAggregate(Type,other params) или RegisterAggregate(MethodInfo acc, MethodInfo merge, other params)

Т.е. вы предлагаете вместо того, чтобы клиент писал:

RegisterFunction(MyFunction, ...);


писать:

RegisterFunction(typeof(MyClass).GetMethod("MyFunction"), ...);


И при это все равно сигнатура функции будет фиксированной?

По-моему мой IFunctionContext по сравнению с этим ну просто Мона Лиза
Re: Дизайн интерфейса
От: Аноним  
Дата: 13.06.09 14:31
Оценка:
По-моему, то что вы пытаетесь сделать, этот «интерфейс» — всего лишь пародия на рефлексию.

Если вы начнете это дальше развивать, то получите жалкое подобие того, что уже (отлично) реализовано в классе System.Reflection.MethodInfo (и других классах этого пространства имен).

Почему бы просто не использовать класс MethodInfo?
Re[2]: Дизайн интерфейса
От: Воронков Василий Россия  
Дата: 13.06.09 14:35
Оценка:
Здравствуйте, Аноним, Вы писали:

А>По-моему, то что вы пытаетесь сделать, этот «интерфейс» — всего лишь пародия на рефлексию.


А>Если вы начнете это дальше развивать, то получите жалкое подобие того, что уже (отлично) реализовано в классе System.Reflection.MethodInfo (и других классах этого пространства имен).


А>Почему бы просто не использовать класс MethodInfo?


Класс MethodInfo — это "контейнер", содержащий метаданные. Интерфейс IFunction — реализация функции. И как раз метаданных о функции он не содержит вообще. Что между ними общего?
Re[7]: Дизайн интерфейса
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 13.06.09 16:27
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, gandjustas, Вы писали:


G>>Да посмотри уже как это в SQL CLR делается.


ВВ>Я повторюсь — у меня не SQL Server. И способ исполнения агрегата отличается.

Ну если SQL база данных, то все равно стадии инциализации, накопления и финализации есть.

ВВ>>>Потом очевидно же подобное решение с т.з. производительности неприемлимо совершенно. С интерфейсами — еще более или менее.

G>>А замеры проводились?

ВВ>Я мерил. Накладные расходы на интерфейс не очень сильные и начинают становиться заметны, когда вызовов *очень* много. А если в запросе будет происходить скан миллиона записей, думаю миллион вызовов через интерфейс покажется назметными с т.з. стоимости.

надо померить не стоимость вызова (и так понятно, что интерфейсный вызов дешевле), а время работы агрегата.
IFunctionContext с его методами будет вносить оверхед, который даже при кодогенерации не исчезнет.

ВВ>В любом случае заниматься подобной оптимизацией с самого начала мне кажется избыточным.

Ну так в том и дело, что использование IFunctionContext — оптимизация, ограничивающая пространство маневра.

G>>Все равно вы придете к динамической кодогенерации, а там уже IFunctionContext станет излишним.

ВВ>Ну вот в SQL CLR он совсем нелишний, кстати.
В каком месте?

G>>так и будет:

G>>RegisterFunction(MethodInfo, other params)
G>>RegisterAggregate(Type,other params) или RegisterAggregate(MethodInfo acc, MethodInfo merge, other params)

ВВ>Т.е. вы предлагаете вместо того, чтобы клиент писал:


ВВ>
ВВ>RegisterFunction(MyFunction, ...);
ВВ>


ВВ>писать:


ВВ>
ВВ>RegisterFunction(typeof(MyClass).GetMethod("MyFunction"), ...);
ВВ>


я этого не предлагаю. Я дал пример самого низкого уровня API.

ВВ>По-моему мой IFunctionContext по сравнению с этим ну просто Мона Лиза

Ага, загадочно улыбается.
Re[3]: Дизайн интерфейса
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 13.06.09 16:29
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, Аноним, Вы писали:


А>>По-моему, то что вы пытаетесь сделать, этот «интерфейс» — всего лишь пародия на рефлексию.


А>>Если вы начнете это дальше развивать, то получите жалкое подобие того, что уже (отлично) реализовано в классе System.Reflection.MethodInfo (и других классах этого пространства имен).


А>>Почему бы просто не использовать класс MethodInfo?


ВВ>Класс MethodInfo — это "контейнер", содержащий метаданные. Интерфейс IFunction — реализация функции. И как раз метаданных о функции он не содержит вообще. Что между ними общего?


Насчет MethodInfo — мимо кассы, но суть вполне правильно указана. Все эти интерфейсы делаются чтобы получить механизм, аналогичный рефлексии.
Re[8]: Дизайн интерфейса
От: Воронков Василий Россия  
Дата: 13.06.09 16:35
Оценка:
Здравствуйте, gandjustas, Вы писали:

ВВ>>Я повторюсь — у меня не SQL Server. И способ исполнения агрегата отличается.

G>Ну если SQL база данных, то все равно стадии инциализации, накопления и финализации есть.

Блин, я же писал — есть две стадии Step и Final. Можно их "смержить" до одного метода, используя специальный флажок для определения стадии. Собственно, по этому поводу я также и хотел посоветоваться.

ВВ>>В любом случае заниматься подобной оптимизацией с самого начала мне кажется избыточным.

G>Ну так в том и дело, что использование IFunctionContext — оптимизация, ограничивающая пространство маневра.

Это не оптимизация. Если посмотреть на интерфейс, то можно увидеть, что это реализация необходимо функциональности "в лоб". И не более того. Мне интересно обсудить сам контракт, а не тот факт интерфейс это или нет. Скорее всего это и не будет интерфейсом.

G>>>Все равно вы придете к динамической кодогенерации, а там уже IFunctionContext станет излишним.

ВВ>>Ну вот в SQL CLR он совсем нелишний, кстати.
G>В каком месте?

SqlContext.
Вообще помимо собственно параметров уже сейчас есть такие задачи как сообщить базе об ошибке и пр. В дальнейшем могут появиться и другие — получить текст запроса и пр. Все равно какой-то "контекст" в том или ином виде нужен.

G>я этого не предлагаю. Я дал пример самого низкого уровня API.


Что мне с этим АПИ делать? Я так и не понял, извините, какой смысл
1) фиксировать сигнатуру методов
2) регистрировать их — неважно на низком или высоком уровне — в виде МетодИнфо.
Re[4]: Дизайн интерфейса
От: Воронков Василий Россия  
Дата: 13.06.09 16:39
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Насчет MethodInfo — мимо кассы, но суть вполне правильно указана. Все эти интерфейсы делаются чтобы получить механизм, аналогичный рефлексии.


Мне всегда казалось, что рефлексия — это прежде всего механизм получения метаданных типов. Возможность создания экземпляров, вызовов — это уже так, фишка. Мне также казалось, у меня совсем другая задача — определить контракт для вызова.
Я в упор не понимаю, почему вы предлагаете мне тут рефлекшин. Как говорится, недостатки очевидны, а бенефиты вы, извините, мне так и не смогли объяснить.
Re[9]: Дизайн интерфейса
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 13.06.09 16:53
Оценка: 7 (1)
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, gandjustas, Вы писали:


ВВ>>>Я повторюсь — у меня не SQL Server. И способ исполнения агрегата отличается.

G>>Ну если SQL база данных, то все равно стадии инциализации, накопления и финализации есть.

ВВ>Блин, я же писал — есть две стадии Step и Final. Можно их "смержить" до одного метода, используя специальный флажок для определения стадии. Собственно, по этому поводу я также и хотел посоветоваться.

Ну правльно. И варианта 2: регистрировать методы парами, объединить их в один класс, реализующий како-либо контракт (явный через интерфейс или неявный).

ВВ>>>В любом случае заниматься подобной оптимизацией с самого начала мне кажется избыточным.

G>>Ну так в том и дело, что использование IFunctionContext — оптимизация, ограничивающая пространство маневра.

ВВ>Это не оптимизация. Если посмотреть на интерфейс, то можно увидеть, что это реализация необходимо функциональности "в лоб".

Ну как-то неправдоподобно. Вот есть в sql функция func(x:int):int, тогда реалзиация в языке "влоб" будет int func(int x).
А за всю гряхную работу по протаскиванию значений от sql в реализацию должен делать код, о котором функция func и не знает.

ВВ>И не более того. Мне интересно обсудить сам контракт, а не тот факт интерфейс это или нет. Скорее всего это и не будет интерфейсом.

Сам контракт — контракт функции.

G>>>>Все равно вы придете к динамической кодогенерации, а там уже IFunctionContext станет излишним.

ВВ>>>Ну вот в SQL CLR он совсем нелишний, кстати.
G>>В каком месте?

ВВ>SqlContext.

ВВ>Вообще помимо собственно параметров уже сейчас есть такие задачи как сообщить базе об ошибке и пр. В дальнейшем могут появиться и другие — получить текст запроса и пр. Все равно какой-то "контекст" в том или ином виде нужен.
Ну это сильно сервисный класс, котороый необходим только в триггерах, видимо из-за их непродуманности.
Функции и агрегаты вполне могут и не обращаться к этому классу.

G>>я этого не предлагаю. Я дал пример самого низкого уровня API.


ВВ>Что мне с этим АПИ делать?

Ничего, я просто первое что я придумал.
Re[5]: Дизайн интерфейса
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 13.06.09 17:07
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, gandjustas, Вы писали:


G>>Насчет MethodInfo — мимо кассы, но суть вполне правильно указана. Все эти интерфейсы делаются чтобы получить механизм, аналогичный рефлексии.


ВВ>Мне всегда казалось, что рефлексия — это прежде всего механизм получения метаданных типов. Возможность создания экземпляров, вызовов — это уже так, фишка. Мне также казалось, у меня совсем другая задача — определить контракт для вызова.

Его не нуно определять, контракт уже есть у метода. Есдинственный способ работать с таким контрактом — рефлекшн.

ВВ>Я в упор не понимаю, почему вы предлагаете мне тут рефлекшин. Как говорится, недостатки очевидны, а бенефиты вы, извините, мне так и не смогли объяснить.

Недостатки у рефлекшена только в скорости, но это лечится динамической кодогенерацией.
Re[3]: Дизайн интерфейса
От: Аноним  
Дата: 14.06.09 11:14
Оценка:
ВВ>Класс MethodInfo — это "контейнер", содержащий метаданные. Интерфейс IFunction — реализация функции. И как раз метаданных о функции он не содержит вообще. Что между ними общего?

Это как так «не содержит»?! А IFunctionContext — это что, не метаданные? Это самые что ни на есть натуральные метаданные, представляющие собой жалкую пародию на класс MethodInfo.

А MethodInfo можно использовать примерно так (саму задачу вы таки не описали, так что конкретнее привести пример не могу):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace UserMethods
{
    class UserFunction
    {
        public UserFunction(object targetObject, string methodName)
        {
            this.targetObject = targetObject;
            methodInfo = targetObject.GetType().GetMethod(methodName);
        }

        public void Invoke()
        {
            methodInfo.Invoke(targetObject, null);
        }

        object targetObject;
        MethodInfo methodInfo;
    }

    class DB
    {
        public void RegisterUserFunction(object targetObject, string name)
        {
            userFunctions.Add(new UserFunction(targetObject, name));
        }

        public void InvokeUserFunctions()
        {
            userFunctions.ForEach(userFunction => userFunction.Invoke());
        }

        List<UserFunction> userFunctions = new List<UserFunction>();
    }

    class SomeUserClass
    {
        public void SomeUserFunction()
        {
            Console.WriteLine("User function is being called.");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            DB db = new DB();

            SomeUserClass userObject = new SomeUserClass();

            db.RegisterUserFunction(userObject, "SomeUserFunction");

            db.InvokeUserFunctions();
        }
    }
}
Re[5]: Дизайн интерфейса
От: Аноним  
Дата: 14.06.09 12:17
Оценка:
ВВ>Мне всегда казалось, что рефлексия — это прежде всего механизм получения метаданных типов. Возможность создания экземпляров, вызовов — это уже так, фишка.

У вас превратное представление о метаданных. Вы не задумаывались, для чего вообще в дотнете используются метаданные? Вот, например, в C++ вообще нет метаданных (что очень плохо), и он без них работает.

По моей информации, полученной из надежных источников, основной областью применения метаданных в дотнете является динамическая кодогенерация, также известная как JIT, а также поддержка компонентной модели.

А в самом деле, зачем мне нужно получать метаданные, если я с ними ничего потом не смогу сделать?
Re[6]: Дизайн интерфейса
От: Воронков Василий Россия  
Дата: 14.06.09 12:55
Оценка:
Здравствуйте, Аноним, Вы писали:

А>У вас превратное представление о метаданных.


Да нет, похоже, это у вас.

А>Вы не задумаывались, для чего вообще в дотнете используются метаданные?


Для получения информации о типах, очевидно.

А>Вот, например, в C++ вообще нет метаданных (что очень плохо), и он без них работает.


Откройте для себя RTTI.

А>По моей информации, полученной из надежных источников, основной областью применения метаданных в дотнете является динамическая кодогенерация, также известная как JIT, а также поддержка компонентной модели.


А вот за эту фразу вам большое спасибо. Улыбнуло. Сильно.

А>А в самом деле, зачем мне нужно получать метаданные, если я с ними ничего потом не смогу сделать?


Не можете ничего сделать как раз потому что у вас превратное представление о метаданных.
Re[4]: Дизайн интерфейса
От: Воронков Василий Россия  
Дата: 14.06.09 12:57
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Это как так «не содержит»?! А IFunctionContext — это что, не метаданные? Это самые что ни на есть натуральные метаданные, представляющие собой жалкую пародию на класс MethodInfo.


Нет, это не метаданные. Это колл-бек интерфейс. Разницу понимаете?

А>А MethodInfo можно использовать примерно так (саму задачу вы таки не описали, так что конкретнее привести пример не могу):


Задачу я описал — механизм регистрации скалярных и агрегатных ф-ций для СКЛ БД.

[skipped]

За пример кода спасибо
Да, а потом мы еще удивляемся — а че все так работает-то медленно? Видимо, дотнет во всем виноват
Re: Дизайн интерфейса
От: Буравчик Россия  
Дата: 14.06.09 15:32
Оценка: 7 (1)
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Пока все. Буду рад любым советам.


CallType — мне не очень понравилось. Проще это все явно в интерфейс включить.

public interface IScalarFunction : IFunction
{
  IFunctionResult Execute(IFunctionParams params);
}

public interface IAggregateFunction : IFunction
{
  IFunctionResult ExecuteOnStep(IFunctionParams params);
  IFunctionResult ExecuteOnFinal(IFunctionParams params);
}


Теперь методы интерфейса стали похожи на обычный вызов функции, что в общем-то логично
Описаны параметры (IFunctionParams) и возвращаемый результат (IFunctionResult).

А вот, что в этих интерфейсах должно быть — это вопрос, который непосредственно завязан на методы IFunctionContext.
Непонятно, например, зачем отдельно выделять SetResultValue<T>, void SetResultBlob, SetResultNull, SetResultZeroBlob.
И непонятны отличия ReportError(FunctionError error) и ReportError(int code, string message).
... << RSDN@Home 1.2.0 alpha 4 rev. 1218>>
Best regards, Буравчик
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.