Как стать автором
Обновить
3
0

.net — разработчик

Отправить сообщение

Главная ошибка при использовании MediatR - использовать MediatR. Конечно, в некоторых сценариях он выглядит крайне полезным, но всегда оказывается раком, стихийно захватывающим проект и превращающим его в комок отвратительной лапши

Добыли и сожгли миллиарды тонн нефти для очередного пыль-в-глаза проекта

хэштег экология

Автомаппер никогда не должен был существовать. Именно ему мы обязаны лучшим примерам "слоистой архитектуры" с десятком слоев DTOшек. Не будь автомаппера, люди бы поленились перегонять раз за разом одни и те же данные из одних дто в другие. А так пожалуйста, порождают монстров

предложить исправление

А может ещё и статьи за вас писать? Куда переводить деньги, чтобы вы могли всегда радовать нас своим дерьмом?

фантастика/прототипы/технологии будущего

Скажите это Билибинской АЭС, которую пора уже выводить из эксплуатации. Живое дряхлое воплощение малых АЭС. Только

Билибинская АТЭЦ, несмотря на свои отличные характеристики, доказала бесперспективность стационарной установки малой мощности

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

Ловите выгоревшего

Эти столики/тумбочки для ног будут рассадником грибка и источником вони. Не взлетит

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

А не будет никакого завтрашнего дня. Вся статья не более чем зелено-популистская сказка и водородная энергетика на текущих технологиях не работает. Более того последние 15 лет увлечения ВИЭ можно охарактеризовать только как фиаско декарбонизации, на фоне чего в европке назревает ядерный ренессанс, но процесс этот совсем не быстрый и для выполнения климатических обязательств в краткосрочной перспективе можно только жечь газ вместо угля. Поэтому можно сказать определенно: в ближайшие годы Газпром будет только богатеть, вангую что в Европе пик потребления природного газа будет пройден только в 50-х.

А вот послезавтрашний день уже другой разговор, надеюсь мои внуки смогут наладить жизнь в условиях свершившегося глобального потепления.

Это все хорошо, но что под капотом? x86 теперь через эмуляцию? PowerShell core по дефолту вместе с WindowsTerminal и, собственно, самим .NET5?

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

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

Извините, накипело

Как я понял, бегло посмотрев на код, смысл всего этого очень прост: собираем и обходим в ширину генераторами приложение как дерево. Всё приложение работает как одна стейт-машина. Похоже что dom обновляется целиком (или реализация diff-рендеринга от меня ускользает). Много бойлерплейта для приложений, для реальных проектов код выйдет слишком многословным. В целом очень интересно, однозначно стоит украсть автора пару приёмов.
Заводить ли зайку решат, конечно, сами. Но лужайку налогами оплачивать нам

Очень круто. Разве что я всегда думал что шарпам в частности и дотнету в целом не достаёт строгости, и фичу с дефолтной реализацией в интерфейсах в C# 8 я воспринял с опаской. Тем паче всегда с ужасом и восхищением я смотрел на то как люди реализуют вещи вроде описанных в статье для чего-то кроме спортивного интереса.
Да поможет господь тем, кому придется поддерживать код на ваших трейтах.
А если серьезно, то очень хотелось бы подробнее узнать какая проблема/задача ( наверняка интересная и нетривиальная) привела к созданию вот этого.

Поделюсь своим рецептом
QueryModel. Обсервится во вьюхе
import { CustomJsonParser, CustomJsonStringify } from "@/utils/JsonHelpers";

const DefaultRowsPerPage: number = 40;

export default class QueryModel<T>
{
	limit: number|null;
	page: number;
	readonly sorts: SortParam<T>[];
	readonly filters: FilterParam<T, keyof T>[];

	private _serverItemsCount: number|null = null;

	public get Hash(): string
	{
		return this.ToUrlSearchParams().toString();
	}

	constructor(qm?: Partial<QueryModel<T>>)
	{
		this.limit = qm?.limit ?? null;
		this.page = qm?.page ?? 0;
		this.sorts = qm?.sorts ?? [];
		this.filters = qm?.filters ?? [];
	}

	public static Create<T>(cfg?: (qm: QueryModel<T>) => void): QueryModel<T>
	{
		let res = new QueryModel<T>({limit: DefaultRowsPerPage, page: 0});
		if(!!cfg) cfg(res);
		return res;
	}

	public ToFilterOnlyModel(): QueryModel<T>
	{
		return new QueryModel<T>({filters: this.filters, sorts: this.sorts});
	}

	public ToUrlSearchParams(): URLSearchParams
	{
		const usp = new URLSearchParams();

		if ( this.limit !== null && this.limit > 0 )
		{
			usp.append('$limit', this.limit.toString());
		}
		if ( this.page > 0 )
		{
			usp.append('$page', this.page.toString());
		}
		if ( this.sorts.length )
		{
			usp.append('$sortby', this.sorts.filter(x => !!x).map(x => `${x![1] ? "-" : ""}${x![0]}`).join(",") );
		}
		if ( this.filters.length )
		{
			for (let [field, expr, vals] of this.filters)
			{
				usp.append(field as string, `${expr}:${stringifyVals(vals)}`);
			}
		}

		return usp;
	}

	public static Parse<T>(queryString: string): QueryModel<T>
	{
		const usp = new URLSearchParams(queryString);

		const limit: number = parseInt(usp.get("$limit") ?? '');
		const page: number = parseInt(usp.get("$page") ?? '');

		const sorts: SortParam<T>[] = usp.getAll('$sortby')
			.map(x => x.split(',')).flat().filter(x => !!x)
			.map(x => x.indexOf('-') === 0 ? [x.slice(1) as keyof T, true] : [x as keyof T, false]);


		let filters: FilterParam<T, keyof T>[] = [];
		for( let [k, v] of usp.entries())
		{
			if(k.includes('$') || !v?.length) continue;
			const vs = v.split(/\:|\,/g);
			let values = vs.splice(1).map(y => !isNaN(Number(y)) ? +y : JSON.parse(`"${y}"`, CustomJsonParser));
			filters.push([k as keyof T, vs[0] as TFilterExpression<T[keyof T]>, values])
		}

		return new QueryModel<T>({
			limit: !isNaN(limit) && isFinite(limit) ? limit : null,
			page: !isNaN(page) && isFinite(page) ? page : 0,
			sorts: sorts,
			filters: filters
		})
	}

	public UnsetLimit(): void
	{
		this.limit = null;
	}

	public SetLimit(limit: number): void
	{
		this.limit = limit;
	}

	public SetTotalItemsCount(cnt: number): void
	{
		this._serverItemsCount = cnt;
	}

	public get MaxPage(): number
	{
		return this.limit == null ? 0 : Math.floor((this._serverItemsCount ?? 0) / this.limit);
	}

	public get Page(): number
	{
		return this.page;
	}

	public set Page(page: number)
	{
		if(page < 0 || page > this.MaxPage) return;
		this.page = page;
	}

	public SetFilter<K extends keyof T = keyof T>(field: K, filterExpr: TFilterExpression<T[K]>, values: T[K][]): void
	{
		let vals = values.filter(v => (
			v !== undefined &&
			v !== null &&
			!(typeof(v) == "string" && !v.length)
		));
		if(!vals.length) return;
		let i = this.filters.findIndex(x => x[0] == field);
		if(i > -1)
		{
			if(this.filters[i][2] === vals) return;
			this.filters.splice(i, 1, [field, filterExpr, vals])
		}
		else
		{
			this.filters.push([field, filterExpr, vals]);
		}

		this.page = 0;
	}

	public HasFilter(field: keyof T): boolean
	{
		return !!this.GetFilter(field)?.length;
	}

	public GetFilter<K extends keyof T = keyof T>(field: keyof T): FilterParam<T, K>|null
	{
		return this.filters.find(x => x[0] == field) as FilterParam<T, K> ?? null;
	}

	public GetFilterValue<K extends keyof T = keyof T>(field: keyof T): T[K][]|null
	{
		return (this.filters.find(x => x[0] == field) as FilterParam<T, K>)?.[2] ?? null;
	}

	public ResetFilter(field: keyof T): void
	{
		let i = this.filters.findIndex(x => x[0] == field);
		if(i < 0) return;
		this.filters.splice(i, 1);
	}

	public ResetAllFilters(): void
	{
		this.filters.splice(0, this.filters.length);
	}

	public SetSort(field: keyof T): void
	{
		let sortI = this.sorts.findIndex(x => x![0] == field);
		if(sortI == -1)
		{
			this.sorts.push([field, false]);
		}
		else
		{
			if(!this.sorts[sortI]![1]) this.sorts.splice(sortI, 1, [field, true]);
			else this.sorts.splice(sortI, 1);
		}
	}

	public GetSort(field: keyof T): [boolean, number] | null
	{
		let sortI = this.sorts.findIndex(x => x![0] == field);
		if(sortI == -1) return null;
		else return [this.sorts[sortI]![1], sortI];
	}

	public ResetAllSort()
	{
		this.sorts.splice(0, this.sorts.length);
	}

	public ResetAll()
	{
		this.ResetAllFilters();
		this.ResetAllSort();
		this.limit = DefaultRowsPerPage;
		this.page = 0;
	}
}

function stringifyVals(x: any[])
{
	return x.map(x => {
		let res = JSON.stringify(x, CustomJsonStringify).trim().replace(/^"?|"?$/g, '');
		if(x instanceof Date) return res.slice(0, 10);
		return  res;
	}).join(",");
}

export type SortParam<T> = [keyof T, boolean] | null;
export type FilterParam<T, K extends keyof T> = [K, TFilterExpression<T[K]>, T[K][]]

Вы меня совсем не поняли.
Ладно, буду писать статью

Не будет нормальной типизации с Vuex, и все библиотеки для его типизации костыли. Выкинь его. Как? Берешь что-то вроде { ModuleName: Vue.observable(new MyStorageModuleName()) } и запихиваешь как плагин и/или даже в window.$myStorage.
Выходит действительно хорошо, использую такой подход на продакшене второй год. Vuex собираюсь откапывать для новых проектов только в 5-ой версии, где они обещали все с нуля переписать с нормальной поддержкой ts.
Алсо класс-синтаксис компонентов самому очень нравится, но, наверное, от этого надо уходить, для vue 3 его почти похоронили

Боюсь, что большая часть из этих 2.9% находится в местах лишения свободы. Думаю, вам было бы лучше избежать близкого знакомства с этими людьми

Информация

В рейтинге
Не участвует
Откуда
Санкт-Петербург, Санкт-Петербург и область, Россия
Дата рождения
Зарегистрирован
Активность