mirror of
https://github.com/pese-git/cherrypick.git
synced 2026-01-24 05:25:19 +00:00
refactor: unify DIAdapter with generics, ensure type-safety & scalability in benchmark_di
- Refactor DIAdapter to generic abstract class; align interfaces for Cherrypick, GetIt, Riverpod. - Remove all dynamic/object usage from dependency registration and bench scenarios. - Universal getUniversalRegistration function now fully type-safe for all DIs. - Fix teardown and lifecycle for RiverpodAdapter to prevent disposed Container errors. - Update CLI and benchmark entry points; validated all scenarios and stress modes for each DI adapter.
This commit is contained in:
@@ -30,11 +30,8 @@ class BenchmarkCliRunner {
|
|||||||
for (final c in config.chainCounts) {
|
for (final c in config.chainCounts) {
|
||||||
for (final d in config.nestDepths) {
|
for (final d in config.nestDepths) {
|
||||||
BenchmarkResult benchResult;
|
BenchmarkResult benchResult;
|
||||||
final di = config.di == 'getit'
|
if (config.di == 'getit') {
|
||||||
? GetItAdapter()
|
final di = GetItAdapter();
|
||||||
: config.di == 'riverpod'
|
|
||||||
? RiverpodAdapter()
|
|
||||||
: CherrypickDIAdapter();
|
|
||||||
if (scenario == UniversalScenario.asyncChain) {
|
if (scenario == UniversalScenario.asyncChain) {
|
||||||
final benchAsync = UniversalChainAsyncBenchmark(di,
|
final benchAsync = UniversalChainAsyncBenchmark(di,
|
||||||
chainCount: c, nestingDepth: d, mode: mode,
|
chainCount: c, nestingDepth: d, mode: mode,
|
||||||
@@ -54,6 +51,49 @@ class BenchmarkCliRunner {
|
|||||||
repeats: config.repeats,
|
repeats: config.repeats,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
} else if (config.di == 'riverpod') {
|
||||||
|
final di = RiverpodAdapter();
|
||||||
|
if (scenario == UniversalScenario.asyncChain) {
|
||||||
|
final benchAsync = UniversalChainAsyncBenchmark(di,
|
||||||
|
chainCount: c, nestingDepth: d, mode: mode,
|
||||||
|
);
|
||||||
|
benchResult = await BenchmarkRunner.runAsync(
|
||||||
|
benchmark: benchAsync,
|
||||||
|
warmups: config.warmups,
|
||||||
|
repeats: config.repeats,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
final benchSync = UniversalChainBenchmark(di,
|
||||||
|
chainCount: c, nestingDepth: d, mode: mode, scenario: scenario,
|
||||||
|
);
|
||||||
|
benchResult = await BenchmarkRunner.runSync(
|
||||||
|
benchmark: benchSync,
|
||||||
|
warmups: config.warmups,
|
||||||
|
repeats: config.repeats,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
final di = CherrypickDIAdapter();
|
||||||
|
if (scenario == UniversalScenario.asyncChain) {
|
||||||
|
final benchAsync = UniversalChainAsyncBenchmark(di,
|
||||||
|
chainCount: c, nestingDepth: d, mode: mode,
|
||||||
|
);
|
||||||
|
benchResult = await BenchmarkRunner.runAsync(
|
||||||
|
benchmark: benchAsync,
|
||||||
|
warmups: config.warmups,
|
||||||
|
repeats: config.repeats,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
final benchSync = UniversalChainBenchmark(di,
|
||||||
|
chainCount: c, nestingDepth: d, mode: mode, scenario: scenario,
|
||||||
|
);
|
||||||
|
benchResult = await BenchmarkRunner.runSync(
|
||||||
|
benchmark: benchSync,
|
||||||
|
warmups: config.warmups,
|
||||||
|
repeats: config.repeats,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
final timings = benchResult.timings;
|
final timings = benchResult.timings;
|
||||||
timings.sort();
|
timings.sort();
|
||||||
var mean = timings.reduce((a, b) => a + b) / timings.length;
|
var mean = timings.reduce((a, b) => a + b) / timings.length;
|
||||||
|
|||||||
@@ -1,13 +1,18 @@
|
|||||||
import 'package:cherrypick/cherrypick.dart';
|
import 'package:cherrypick/cherrypick.dart';
|
||||||
import 'di_adapter.dart';
|
import 'di_adapter.dart';
|
||||||
|
|
||||||
/// DIAdapter implementation for the CherryPick DI library using registration callbacks.
|
/// Универсальный DIAdapter для CherryPick с поддержкой subScope без дублирования логики.
|
||||||
class CherrypickDIAdapter implements DIAdapter {
|
class CherrypickDIAdapter extends DIAdapter<Scope> {
|
||||||
Scope? _scope;
|
Scope? _scope;
|
||||||
|
final bool _isSubScope;
|
||||||
|
|
||||||
|
CherrypickDIAdapter([Scope? scope, this._isSubScope = false]) {
|
||||||
|
_scope = scope;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void setupDependencies(void Function(dynamic container) registration) {
|
void setupDependencies(void Function(Scope container) registration) {
|
||||||
_scope = CherryPick.openRootScope();
|
_scope ??= CherryPick.openRootScope();
|
||||||
registration(_scope!);
|
registration(_scope!);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,45 +26,18 @@ class CherrypickDIAdapter implements DIAdapter {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void teardown() {
|
void teardown() {
|
||||||
|
if (!_isSubScope) {
|
||||||
CherryPick.closeRootScope();
|
CherryPick.closeRootScope();
|
||||||
_scope = null;
|
_scope = null;
|
||||||
}
|
}
|
||||||
|
// SubScope teardown не требуется
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
CherrypickDIAdapter openSubScope(String name) {
|
CherrypickDIAdapter openSubScope(String name) {
|
||||||
final sub = _scope!.openSubScope(name);
|
return CherrypickDIAdapter(_scope!.openSubScope(name), true);
|
||||||
return _CherrypickSubScopeAdapter(sub);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> waitForAsyncReady() async {}
|
Future<void> waitForAsyncReady() async {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Internal adapter for a CherryPick sub-scope (callbacks based).
|
|
||||||
class _CherrypickSubScopeAdapter extends CherrypickDIAdapter {
|
|
||||||
final Scope _subScope;
|
|
||||||
_CherrypickSubScopeAdapter(this._subScope);
|
|
||||||
|
|
||||||
@override
|
|
||||||
void setupDependencies(void Function(dynamic container) registration) {
|
|
||||||
registration(_subScope);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
T resolve<T extends Object>({String? named}) =>
|
|
||||||
named == null ? _subScope.resolve<T>() : _subScope.resolve<T>(named: named);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<T> resolveAsync<T extends Object>({String? named}) async =>
|
|
||||||
named == null ? await _subScope.resolveAsync<T>() : await _subScope.resolveAsync<T>(named: named);
|
|
||||||
|
|
||||||
@override
|
|
||||||
void teardown() {
|
|
||||||
// subScope teardown не требуется
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
CherrypickDIAdapter openSubScope(String name) {
|
|
||||||
return _CherrypickSubScopeAdapter(_subScope.openSubScope(name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,24 +1,21 @@
|
|||||||
/// Абстракция для DI-адаптера с использованием функций регистрации.
|
/// Универсальная абстракция для DI-адаптера с унифицированной функцией регистрации.
|
||||||
///
|
/// Теперь для каждого адаптера задаём строгий generic тип контейнера.
|
||||||
/// Позволяет использовать любые DI-контейнеры: и модульные, и безмодульные.
|
abstract class DIAdapter<TContainer> {
|
||||||
abstract class DIAdapter {
|
/// Устанавливает зависимости с помощью строго типизированного контейнера.
|
||||||
/// Устанавливает зависимости с помощью одной функции регистрации.
|
void setupDependencies(void Function(TContainer container) registration);
|
||||||
///
|
|
||||||
/// Функция принимает выбранный DI-контейнер, задаваемый реализацией.
|
|
||||||
void setupDependencies(void Function(dynamic container) registration);
|
|
||||||
|
|
||||||
/// Резолвит (возвращает) экземпляр типа [T] (по имени, если требуется).
|
/// Резолвит (возвращает) экземпляр типа [T] (по имени, если требуется).
|
||||||
T resolve<T extends Object>({String? named});
|
T resolve<T extends Object>({String? named});
|
||||||
|
|
||||||
/// Асинхронно резолвит экземпляр типа [T].
|
/// Асинхронно резолвит экземпляр типа [T] (если нужно).
|
||||||
Future<T> resolveAsync<T extends Object>({String? named});
|
Future<T> resolveAsync<T extends Object>({String? named});
|
||||||
|
|
||||||
/// Уничтожает/отчищает DI-контейнер.
|
/// Уничтожает/отчищает DI-контейнер.
|
||||||
void teardown();
|
void teardown();
|
||||||
|
|
||||||
/// Открывает дочерний под-scope (если применимо).
|
/// Открывает дочерний scope и возвращает новый адаптер (если поддерживается).
|
||||||
DIAdapter openSubScope(String name);
|
DIAdapter<TContainer> openSubScope(String name);
|
||||||
|
|
||||||
/// Ожидание готовности DI контейнера (нужно для async DI, например get_it)
|
/// Ожидание готовности DI контейнера (если нужно для async DI).
|
||||||
Future<void> waitForAsyncReady();
|
Future<void> waitForAsyncReady() async {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,73 +1,58 @@
|
|||||||
import 'package:get_it/get_it.dart';
|
import 'package:get_it/get_it.dart';
|
||||||
import 'di_adapter.dart';
|
import 'di_adapter.dart';
|
||||||
|
|
||||||
class GetItAdapter implements DIAdapter {
|
/// Универсальный DIAdapter для GetIt c поддержкой scopes и строгой типизацией.
|
||||||
|
class GetItAdapter extends DIAdapter<GetIt> {
|
||||||
late GetIt _getIt;
|
late GetIt _getIt;
|
||||||
|
final String? _scopeName;
|
||||||
|
final bool _isSubScope;
|
||||||
|
bool _scopePushed = false;
|
||||||
|
|
||||||
|
/// Основной (root) и subScope-конструкторы.
|
||||||
|
GetItAdapter({GetIt? instance, String? scopeName, bool isSubScope = false})
|
||||||
|
: _scopeName = scopeName,
|
||||||
|
_isSubScope = isSubScope {
|
||||||
|
if (instance != null) {
|
||||||
|
_getIt = instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void setupDependencies(void Function(dynamic container) registration) {
|
void setupDependencies(void Function(GetIt container) registration) {
|
||||||
|
if (_isSubScope) {
|
||||||
|
// Создаём scope через pushNewScope с init
|
||||||
|
_getIt.pushNewScope(
|
||||||
|
scopeName: _scopeName,
|
||||||
|
init: (getIt) => registration(getIt),
|
||||||
|
);
|
||||||
|
_scopePushed = true;
|
||||||
|
} else {
|
||||||
_getIt = GetIt.asNewInstance();
|
_getIt = GetIt.asNewInstance();
|
||||||
registration(_getIt);
|
registration(_getIt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
T resolve<T extends Object>({String? named}) => _getIt<T>(instanceName: named);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<T> resolveAsync<T extends Object>({String? named}) async => _getIt<T>(instanceName: named);
|
|
||||||
|
|
||||||
@override
|
|
||||||
void teardown() => _getIt.reset();
|
|
||||||
|
|
||||||
@override
|
|
||||||
DIAdapter openSubScope(String name) {
|
|
||||||
// Открываем новый scope и возвращаем адаптер, который в setupDependencies будет использовать init.
|
|
||||||
return _GetItScopeAdapter(_getIt, name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> waitForAsyncReady() async {
|
T resolve<T extends Object>({String? named}) =>
|
||||||
await _getIt.allReady();
|
_getIt<T>(instanceName: named);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _GetItScopeAdapter implements DIAdapter {
|
|
||||||
final GetIt _getIt;
|
|
||||||
final String _scopeName;
|
|
||||||
bool _scopePushed = false;
|
|
||||||
void Function(dynamic container)? _pendingRegistration;
|
|
||||||
|
|
||||||
_GetItScopeAdapter(this._getIt, this._scopeName);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void setupDependencies(void Function(dynamic container) registration) {
|
Future<T> resolveAsync<T extends Object>({String? named}) async =>
|
||||||
_pendingRegistration = registration;
|
_getIt<T>(instanceName: named);
|
||||||
// Создаём scope через pushNewScope с init для правильной регистрации
|
|
||||||
_getIt.pushNewScope(
|
|
||||||
scopeName: _scopeName,
|
|
||||||
init: (getIt) => _pendingRegistration?.call(getIt),
|
|
||||||
);
|
|
||||||
_scopePushed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
T resolve<T extends Object>({String? named}) => _getIt<T>(instanceName: named);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<T> resolveAsync<T extends Object>({String? named}) async => _getIt<T>(instanceName: named);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void teardown() {
|
void teardown() {
|
||||||
if (_scopePushed) {
|
if (_isSubScope && _scopePushed) {
|
||||||
_getIt.popScope();
|
_getIt.popScope();
|
||||||
_scopePushed = false;
|
_scopePushed = false;
|
||||||
|
} else {
|
||||||
|
_getIt.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
DIAdapter openSubScope(String name) {
|
GetItAdapter openSubScope(String name) =>
|
||||||
return _GetItScopeAdapter(_getIt, name);
|
GetItAdapter(instance: _getIt, scopeName: name, isSubScope: true);
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> waitForAsyncReady() async {
|
Future<void> waitForAsyncReady() async {
|
||||||
|
|||||||
@@ -1,67 +1,71 @@
|
|||||||
import 'package:riverpod/riverpod.dart';
|
import 'package:riverpod/riverpod.dart';
|
||||||
import 'di_adapter.dart';
|
import 'di_adapter.dart';
|
||||||
|
|
||||||
/// RiverpodAdapter реализует DIAdapter для универсального бенчмарка через Riverpod.
|
/// Унифицированный DIAdapter для Riverpod с поддержкой scopes и строгой типизацией.
|
||||||
class RiverpodAdapter implements DIAdapter {
|
class RiverpodAdapter extends DIAdapter<Map<String, ProviderBase<Object?>>> {
|
||||||
late ProviderContainer _container;
|
ProviderContainer? _container;
|
||||||
late final Map<String?, ProviderBase<Object?>> _namedProviders;
|
final Map<String, ProviderBase<Object?>> _namedProviders;
|
||||||
final ProviderContainer? _parent;
|
final ProviderContainer? _parent;
|
||||||
|
final bool _isSubScope;
|
||||||
|
|
||||||
// Основной конструктор
|
RiverpodAdapter({
|
||||||
RiverpodAdapter() : _parent = null {
|
ProviderContainer? container,
|
||||||
_namedProviders = <String?, ProviderBase<Object?>>{};
|
Map<String, ProviderBase<Object?>>? providers,
|
||||||
}
|
ProviderContainer? parent,
|
||||||
|
bool isSubScope = false,
|
||||||
// Внутренний конструктор для дочерних скоупов
|
}) : _container = container,
|
||||||
RiverpodAdapter._child(this._container, this._namedProviders, this._parent);
|
_namedProviders = providers ?? <String, ProviderBase<Object?>>{},
|
||||||
|
_parent = parent,
|
||||||
|
_isSubScope = isSubScope;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void setupDependencies(void Function(dynamic container) registration) {
|
void setupDependencies(void Function(Map<String, ProviderBase<Object?>> container) registration) {
|
||||||
// Для главного контейнера
|
_container ??= _parent == null
|
||||||
_container = _parent == null
|
|
||||||
? ProviderContainer()
|
? ProviderContainer()
|
||||||
: ProviderContainer(parent: _parent);
|
: ProviderContainer(parent: _parent);
|
||||||
registration(_namedProviders);
|
registration(_namedProviders);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Регистрировать провайдеры нужно по имени-сервису.
|
|
||||||
/// Пример: container['SomeClass'] = Provider((ref) => SomeClass());
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
T resolve<T extends Object>({String? named}) {
|
T resolve<T extends Object>({String? named}) {
|
||||||
final provider = _namedProviders[named ?? T.toString()];
|
final key = named ?? T.toString();
|
||||||
|
final provider = _namedProviders[key];
|
||||||
if (provider == null) {
|
if (provider == null) {
|
||||||
throw Exception('Provider not found for $named');
|
throw Exception('Provider not found for $key');
|
||||||
}
|
}
|
||||||
return _container.read(provider) as T;
|
return _container!.read(provider) as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<T> resolveAsync<T extends Object>({String? named}) async {
|
Future<T> resolveAsync<T extends Object>({String? named}) async {
|
||||||
final provider = _namedProviders[named ?? T.toString()];
|
final key = named ?? T.toString();
|
||||||
|
final provider = _namedProviders[key];
|
||||||
if (provider == null) {
|
if (provider == null) {
|
||||||
throw Exception('Provider not found for $named');
|
throw Exception('Provider not found for $key');
|
||||||
}
|
}
|
||||||
// Если это FutureProvider — используем .future
|
// Если это FutureProvider — используем .future
|
||||||
if (provider.runtimeType.toString().contains('FutureProvider')) {
|
if (provider.runtimeType.toString().contains('FutureProvider')) {
|
||||||
final result = await _container.read((provider as dynamic).future);
|
return await _container!.read((provider as dynamic).future) as T;
|
||||||
return result as T;
|
|
||||||
}
|
}
|
||||||
return resolve<T>(named: named);
|
return resolve<T>(named: named);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void teardown() {
|
void teardown() {
|
||||||
_container.dispose();
|
_container?.dispose();
|
||||||
|
_container = null;
|
||||||
_namedProviders.clear();
|
_namedProviders.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
DIAdapter openSubScope(String name) {
|
RiverpodAdapter openSubScope(String name) {
|
||||||
// Создаём дочерний scope через новый контейнер с parent
|
final newContainer = ProviderContainer(parent: _container);
|
||||||
final childContainer = ProviderContainer(parent: _container);
|
return RiverpodAdapter(
|
||||||
// Провайдеры будут унаследованы (immutable копия), но при желании можно их расширять в дочернем scope.
|
container: newContainer,
|
||||||
return RiverpodAdapter._child(childContainer, Map.of(_namedProviders), _container);
|
providers: Map.of(_namedProviders),
|
||||||
|
parent: _container,
|
||||||
|
isSubScope: true,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -6,10 +6,12 @@ import '../di_adapters/get_it_adapter.dart';
|
|||||||
import 'universal_chain_module.dart';
|
import 'universal_chain_module.dart';
|
||||||
import 'package:riverpod/riverpod.dart' as rp;
|
import 'package:riverpod/riverpod.dart' as rp;
|
||||||
|
|
||||||
/// Возвращает универсальную функцию регистрации зависимостей,
|
/// Унифицированный generic-колбэк для регистрации зависимостей,
|
||||||
/// подходящую под выбранный DI-адаптер.
|
/// подходящий под выбранный DI-адаптер.
|
||||||
void Function(dynamic) getUniversalRegistration(
|
typedef Registration<TContainer> = void Function(TContainer);
|
||||||
DIAdapter adapter, {
|
|
||||||
|
Registration<TContainer> getUniversalRegistration<TContainer>(
|
||||||
|
DIAdapter<TContainer> adapter, {
|
||||||
required int chainCount,
|
required int chainCount,
|
||||||
required int nestingDepth,
|
required int nestingDepth,
|
||||||
required UniversalBindingMode bindingMode,
|
required UniversalBindingMode bindingMode,
|
||||||
@@ -25,8 +27,9 @@ void Function(dynamic) getUniversalRegistration(
|
|||||||
scenario: scenario,
|
scenario: scenario,
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
};
|
} as Registration<TContainer>;
|
||||||
} else if (adapter is GetItAdapter || adapter.runtimeType.toString().contains('GetItScopeAdapter')) {
|
}
|
||||||
|
if (adapter is GetItAdapter) {
|
||||||
return (getIt) {
|
return (getIt) {
|
||||||
switch (scenario) {
|
switch (scenario) {
|
||||||
case UniversalScenario.asyncChain:
|
case UniversalScenario.asyncChain:
|
||||||
@@ -82,7 +85,6 @@ void Function(dynamic) getUniversalRegistration(
|
|||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case UniversalBindingMode.asyncStrategy:
|
case UniversalBindingMode.asyncStrategy:
|
||||||
// getIt не поддерживает асинх. factory напрямую, но можно так:
|
|
||||||
getIt.registerSingletonAsync<UniversalService>(
|
getIt.registerSingletonAsync<UniversalService>(
|
||||||
() async => UniversalServiceImpl(
|
() async => UniversalServiceImpl(
|
||||||
value: depName,
|
value: depName,
|
||||||
@@ -108,14 +110,11 @@ void Function(dynamic) getUniversalRegistration(
|
|||||||
getIt<UniversalService>(instanceName: depName),
|
getIt<UniversalService>(instanceName: depName),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
} as Registration<TContainer>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Riverpod
|
if (adapter is DIAdapter<Map<String, rp.ProviderBase<Object?>>> && adapter.runtimeType.toString().contains('RiverpodAdapter')) {
|
||||||
if (adapter.runtimeType.toString().contains('RiverpodAdapter')) {
|
|
||||||
// Регистрация Provider-ов по универсальному сценарию
|
|
||||||
return (providers) {
|
return (providers) {
|
||||||
// providers это Map<String, ProviderBase<Object?>>
|
|
||||||
switch (scenario) {
|
switch (scenario) {
|
||||||
case UniversalScenario.register:
|
case UniversalScenario.register:
|
||||||
providers['UniversalService'] = rp.Provider<UniversalService>((ref) => UniversalServiceImpl(value: 'reg', dependency: null));
|
providers['UniversalService'] = rp.Provider<UniversalService>((ref) => UniversalServiceImpl(value: 'reg', dependency: null));
|
||||||
@@ -135,7 +134,6 @@ void Function(dynamic) getUniversalRegistration(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Alias для последнего (универсальное имя)
|
|
||||||
final depName = '${chainCount}_$nestingDepth';
|
final depName = '${chainCount}_$nestingDepth';
|
||||||
providers['UniversalService'] = rp.Provider<UniversalService>((ref) => ref.watch(providers[depName] as rp.ProviderBase<UniversalService>));
|
providers['UniversalService'] = rp.Provider<UniversalService>((ref) => ref.watch(providers[depName] as rp.ProviderBase<UniversalService>));
|
||||||
break;
|
break;
|
||||||
@@ -157,15 +155,14 @@ void Function(dynamic) getUniversalRegistration(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Alias для последнего (универсальное имя)
|
|
||||||
final depName = '${chainCount}_$nestingDepth';
|
final depName = '${chainCount}_$nestingDepth';
|
||||||
providers['UniversalService'] = rp.FutureProvider<UniversalService>((ref) async {
|
providers['UniversalService'] = rp.FutureProvider<UniversalService>((ref) async {
|
||||||
return await ref.watch(providers[depName]!.future) as UniversalService;
|
return await ref.watch(providers[depName]!.future) as UniversalService;
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
} as Registration<TContainer>;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw UnsupportedError('Unknown DIAdapter type: ${adapter.runtimeType}');
|
throw UnsupportedError('Unknown DIAdapter type: [38;5;3m${adapter.runtimeType}[0m');
|
||||||
}
|
}
|
||||||
|
|||||||
14
pubspec.lock
14
pubspec.lock
@@ -5,23 +5,23 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: _fe_analyzer_shared
|
name: _fe_analyzer_shared
|
||||||
sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab"
|
sha256: "45cfa8471b89fb6643fe9bf51bd7931a76b8f5ec2d65de4fb176dba8d4f22c77"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "76.0.0"
|
version: "73.0.0"
|
||||||
_macros:
|
_macros:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: dart
|
description: dart
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.3.3"
|
version: "0.3.2"
|
||||||
analyzer:
|
analyzer:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: analyzer
|
name: analyzer
|
||||||
sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e"
|
sha256: "4959fec185fe70cce007c57e9ab6983101dbe593d2bf8bbfb4453aaec0cf470a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.11.0"
|
version: "6.8.0"
|
||||||
ansi_styles:
|
ansi_styles:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -298,10 +298,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: macros
|
name: macros
|
||||||
sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656"
|
sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.3-main.0"
|
version: "0.1.2-main.4"
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
Reference in New Issue
Block a user