То, что вы пытаетесь достичь, это хорошо, мне действительно нравится такой синтаксис, и я думаю, что он довольно гибкий. Однако я считаю, что вам нужно лучше разрабатывать свои API.
Код читабелен и почти красив, но его трудно понять, в первую очередь из-за большого количества обобщений, которые не имеют особого смысла, если вы не знаете точно, что означает каждый тип. Я бы по возможности использовал вывод общего типа, чтобы устранить некоторые из них. Для этого рассмотрите возможность использования универсальных методов вместо универсальных типов.
Некоторые предложения по синтаксису (у меня сейчас нет компилятора, поэтому они в основном идеи):
Использовать анонимные типы вместо словарей
Тривиально написать помощника, который преобразует анонимный тип в словарь, но я думаю, что это значительно улучшает запись, и вам не нужно писать new Dictionary<string, object>
.
Использовать Tuple.Create
Этот статический метод был создан, чтобы избежать явного указания типов.
Создание обёртки со строгим шрифтом для DataReader
Это убрало бы эти уродливые преобразования повсюду - и действительно, вам действительно нужен доступ к DataReader
в этой лямбде?
Я проиллюстрирую это кодом для ваших примеров.
Престижность Дэвиду Харкнессу за идею цепочки.
var tuples = new DataAccess ("select ProductId, AvailableQuantity from Shop.Product where ShopId = @shopId")
.With (new { shopId = this.Shop.Id }) // map parameters to values
.ReadMany (row =>
Tuple.Create (row.Value<int> ("ProductId"), row.Value<int> ("AvailableQuantity")));
var strings = new DataAccess ("select distinct ProductName from Shop.Product")
.ReadMany (row => row.Value<string> ("ProductName"));
Я также вижу расширение для обработки выделения одной строки:
var productName = new DataAccess ("select ProductName from Shop.Product where ProductId = @productId")
.With (new { productId = this.SelectedProductId }) // whatever
.ReadOne (row => row.Value<string> ("ProductName"));
Это черновик для Row
класса:
class Row {
DataReader reader;
public Row (DataReader reader)
{
this.reader = reader;
}
public T Value<T> (string column)
{
return (T) Convert.ChangeType (reader [column], typeof (T));
}
}
Он создается для вызовов ReadOne
и ReadMany
и обеспечивает удобный (и ограниченный) доступ к базовому DataReader
для лямбда-селектора.