public class ListView { public ListView(List<string> columns, List<List<object>> data) { Columns = columns; Data = data; } public List<string> Columns { get; } public List<List<object>> Data { get; } } public class ListViewBuilder<T> { public class ListViewBuilderColumn { public ListViewBuilderColumn(string name, Func<T, object> valueSelector) { Name = name; ValueSelector = valueSelector; } public string Name { get; } public Func<T, object> ValueSelector { get; } } private readonly List<ListViewBuilderColumn> Columns = new(); public ListViewBuilder<T> AddColumn(string columnName, Func<T, object> valueSelector) { Columns.Add(new ListViewBuilderColumn(columnName, valueSelector)); return this; } public ListView Build(IEnumerable<T> items) { var columns = Columns.Select(x => x.Name).ToList(); var data = items.Select(x => Columns.Select(y => y.ValueSelector(x)).ToList()).ToList(); return new ListView(columns, data); } } // Example usage: return new ListViewBuilder<BasicDebtorArticle>() .AddColumn("ArticleId", x => x.ArticleId) .AddColumn("DebtorId", x => x.DebtorId) .AddColumn("DebtorArticleId", x => x.DebtorArticleId) .AddColumn("ArticleDescription", x => x.ArticleDescription) .Build(articles);
Convert data back in typescript:
export interface IListView { columns: string[]; data: Array<any[]>; } export function mapListView<T>(listView: IListView): T[] { const columns = listView.columns.map((name, i) => ({ index: i, name: name })); return listView.data.map((row) => { const item: any = {}; for (const { index, name } of columns) item[name] = row[index]; return item as T; }); } async getAllDebtorArticles(debtorId: string): Promise<IDebtorArticle[]> { const listView = await appDependencies.IRestApi.request(`api/article/debtor/${debtorId}`).getData<IListView>(); return mapListView<IDebtorArticle>(listView); }
744000cookie-checkC# ListView Builder