Здравствуйте, Буравчик, Вы писали:
Б>CallType — мне не очень понравилось. Проще это все явно в интерфейс включить.
У меня тоже есть сомнения по поводу CallType. Но вербализировать не могу. А есть ли какие-то причины, можете объяснить почему это плохо?
Б>Теперь методы интерфейса стали похожи на обычный вызов функции, что в общем-то логично
В вашем варианте получается, что при реализации IAggregateFunction придется реализовать метод Execute из интерфейса IScalarFunction, который не нужен.
Тогда уж так:
public interface IScalarFunction : IFunction
{
IFunctionResult Execute(IFunctionParams params);
}
public interface IAggregateFunction : IFunction
{
IFunctionResult ExecuteOnFinal(IFunctionParams params);
}
Но при этом IFunction все равно пустой получается
Кстати, IFunctionContext нужен не только для передачи значений. В противном случае можно все это вообще упростить до:
object Execute(params object[] args);
Я вообще думал еще и о таком варианте:
public interface IFunction
{
IFunctionResult Execute(IFunctionParams params);
}
public interface IAggregateFunction : IFunction
{
CallType CallType { get; set; }
}
По дизайну ИМХО правильно — по большому счет агрегат это скалярная функция, которая имеет особенности в плане выполнения.
Но тут опять появляется этот самый колл-тайп.
Б>А вот, что в этих интерфейсах должно быть — это вопрос, который непосредственно завязан на методы IFunctionContext.
Б>Непонятно, например, зачем отдельно выделять SetResultValue<T>, void SetResultBlob, SetResultNull, SetResultZeroBlob.
SetResultValue<T> — возвращает тип реализующий IConvertible, благодаря генерику даже можем избежать лишней упаковки-распаковки.
SetResultBlob — массив байт, IConvertible не реализует.
SetResultNull — специальное значение, DBNull.
SetResultZeroBlob — тут особый контракт вызова, блоб заполненный нулями указанной длины.
Б>И непонятны отличия ReportError(FunctionError error) и ReportError(int code, string message).
ReportError(FunctionError error) — одна из стандартных ошибок (выбор по энуму)
ReportError(int code, string message) — пользовательская ошибка.
Если есть предложения, как это оформить по-другому, буду рад выслушать.
Здравствуйте, Воронков Василий, Вы писали:
ВВ>У меня тоже есть сомнения по поводу CallType. Но вербализировать не могу. А есть ли какие-то причины, можете объяснить почему это плохо?
Да не плохо это. Просто при определенном раскладе этот тип становится не нужным.
Т.е. если в итоге будет принято решение об одном интерфейсе IFunction { execute }, то CallType останется.
Если разделить на два интерфейса Scalar и Agregate, и в добавок в Aggregate выделить отдельные методы (step и final), то CallType станет не нужным.
Другое дело, что второй вариант, на мой взгляд более правильный => CallType не нужен.
Б>>Теперь методы интерфейса стали похожи на обычный вызов функции, что в общем-то логично
ВВ>В вашем варианте получается, что при реализации IAggregateFunction придется реализовать метод Execute из интерфейса IScalarFunction, который не нужен.
Да, напутал я. Должно быть как-то так.
public interface IScalarFunction : IFunction
{
IFunctionResult Execute(IFunctionParams params);
}
public interface IAggregateFunction : IFunction
{
void ExecuteOnStep(...);
IFunctionResult ExecuteOnFinal(...);
}
ВВ>Тогда уж так:
ВВ>public interface IAggregateFunction : IFunction
ВВ>{
ВВ> IFunctionResult ExecuteOnFinal(IFunctionParams params);
ВВ>}
ВВ>[/c#]
Как определить в каком режиме (step, final) вызывает aggregate?
ВВ>Но при этом IFunction все равно пустой получается
А нужен ли вообще данный интерфейс? Кто на него завязан будет и что делать будет?
Но даже если останется пустой. Сейчас пустой — потом не пустой. Если это добавляет понятности коду — почему нет?
Более того, если Вам нужно определять является ли данный класс реализацией пользовательской функции, даже пустой интерфейс будет полезен.
ВВ>Кстати, IFunctionContext нужен не только для передачи значений. В противном случае можно все это вообще упростить до:
Я в IFunctionContext увидел:
1. Получение параметров вызова функции
2. Предача результата функции.
п.1 реализауется прямой передачей параметров, п.2. реализуется IFunctionResult
Что еще?
ВВ>... по большому счет агрегат это скалярная функция, которая имеет особенности в плане выполнения.
В целом согласен. Но в данном случае их равнять нельзя.
Б>>А вот, что в этих интерфейсах должно быть — это вопрос, который непосредственно завязан на методы IFunctionContext.
ВВ>Если есть предложения, как это оформить по-другому, буду рад выслушать.
Например, так
class ValueResult<T>: IFunctionResult
class BlobResult: IFunctionResult
{
BlobResult(byte[]);
BlobResult(); // zero blob
}
class NullResult: IFunctionResult
class ErrorResult: IFunctionResult
{
ErrorResult(FunctionError); // standard error
ErrorResult(code, msg); // user error
}
Использование:
// вычисляет сумму чисел, хранящихся как строки
// StringSum("123", "123", "3") = 249
class StringSumFunction: IAggregateFunction
{
long sum = 0;
bool error = false;
void ExecuteOnStep(params)
{
if (error)
return
if (является_числом (params[str])) then
sum += parse(params[str])
else
error = true;
}
IFunctionResult ExecuteOnFinal (...)
{
if (error)
return ErrorResult(0, "Не могу прочитать число")
else
return ValueResult<long>(sum);
}
}
... << RSDN@Home 1.2.0 alpha 4 rev. 1218>>