docs(binding,docs): clarify .singleton() with .toInstance() behavior in docs and API

- Add an explicit note and warning about the effect (or lack thereof) of calling `.singleton()` after `.toInstance()`:
  - in singleton() API doc-comment in binding.dart,
  - in README.md (after all binding usage patterns),
  - in full_tutorial_en.md and full_tutorial_ru.md.
- Explain that `.singleton()` has no effect on objects registered with `.toInstance()` — they are always single instance.
- Recommend `.singleton()` only for providers (toProvide/toProvideAsync), not direct instances.
- Improves clarity and prevents misuse/confusion for end users and future maintainers.
This commit is contained in:
Sergey Penkovsky
2025-09-08 10:46:20 +03:00
parent b5b672765e
commit 484061148d
4 changed files with 35 additions and 0 deletions

View File

@@ -185,6 +185,15 @@ void builder(Scope scope) {
> Use this pattern only when you want a “master” singleton. If you expect a new instance per params, **do not** use `.singleton()` on parameterized providers. > Use this pattern only when you want a “master” singleton. If you expect a new instance per params, **do not** use `.singleton()` on parameterized providers.
> **Note about `.singleton()` and `.toInstance()`:**
>
> Calling `.singleton()` after `.toInstance()` does **not** change the bindings behavior: the object passed with `toInstance()` is already a single, constant instance that will be always returned for every resolve.
>
> It is not necessary to use `.singleton()` with an existing object—this call has no effect.
>
> `.singleton()` is only meaningful with providers (such as `toProvide`/`toProvideAsync`), to ensure only one instance is created by the factory.
### Module ### Module
A **Module** is a logical collection point for bindings, designed for grouping and initializing related dependencies. Implement the `builder` method to define how dependencies should be bound within the scope. A **Module** is a logical collection point for bindings, designed for grouping and initializing related dependencies. Implement the `builder` method to define how dependencies should be bound within the scope.

View File

@@ -258,6 +258,13 @@ class Binding<T> {
/// ``` /// ```
/// ///
/// Use this pattern only if you want a master singleton. If you expect a new instance per params, **do not** use `.singleton()` on parameterized providers. /// Use this pattern only if you want a master singleton. If you expect a new instance per params, **do not** use `.singleton()` on parameterized providers.
///
/// **Note about `.singleton()` and `.toInstance()`:**
///
/// Calling `.singleton()` after `.toInstance()` does **not** change the bindings behavior:
/// the object passed with `toInstance()` is already a single, constant instance that will always be returned for every resolve.
/// There is no need to use `.singleton()` with `toInstance()`. This call has no effect.
/// `.singleton()` is only meaningful with providers (`toProvide`, `toProvideAsync`, etc), to ensure only one instance is created by the factory.
Binding<T> singleton() { Binding<T> singleton() {
_resolver?.toSingleton(); _resolver?.toSingleton();
return this; return this;

View File

@@ -107,6 +107,14 @@ final api = scope.resolve<ApiClient>(named: 'mock');
- `.singleton()` — single instance per Scope lifetime - `.singleton()` — single instance per Scope lifetime
- By default, every resolve creates a new object - By default, every resolve creates a new object
> **Note about `.singleton()` and `.toInstance()`:**
>
> Calling `.singleton()` after `.toInstance()` does **not** change the bindings behavior: the object passed with `toInstance()` is already a single, constant instance that will be always returned for every resolve.
>
> It is not necessary to use `.singleton()` with an existing object—this call has no effect.
>
> `.singleton()` is only meaningful with providers (such as `toProvide`/`toProvideAsync`), to ensure only one instance is created by the factory.
### Parameterized bindings ### Parameterized bindings
Allows you to create dependencies with runtime parameters, e.g., a service for a user with a given ID: Allows you to create dependencies with runtime parameters, e.g., a service for a user with a given ID:

View File

@@ -44,6 +44,7 @@ final setupFuture = loadEnvironment();
bind<Environment>().toInstanceAsync(setupFuture); bind<Environment>().toInstanceAsync(setupFuture);
``` ```
> ⚠️ **Важное примечание по использованию toInstance в Module** > ⚠️ **Важное примечание по использованию toInstance в Module**
> >
> Если вы регистрируете цепочку зависимостей через `toInstance` внутри метода `builder` вашего `Module`, нельзя в это же время вызывать `scope.resolve<T>()` для только что объявленного типа. > Если вы регистрируете цепочку зависимостей через `toInstance` внутри метода `builder` вашего `Module`, нельзя в это же время вызывать `scope.resolve<T>()` для только что объявленного типа.
@@ -85,6 +86,7 @@ bind<Environment>().toInstanceAsync(setupFuture);
> **Примечание:** Это ограничение касается только `toInstance`. Для провайдеров (`toProvide`/`toProvideAsync`) и других стратегий вы можете использовать `scope.resolve<T>()` внутри builder без ограничений. > **Примечание:** Это ограничение касается только `toInstance`. Для провайдеров (`toProvide`/`toProvideAsync`) и других стратегий вы можете использовать `scope.resolve<T>()` внутри builder без ограничений.
- **toProvide** — обычная синхронная фабрика. - **toProvide** — обычная синхронная фабрика.
- **toProvideAsync** — асинхронная фабрика (например, если нужно дожидаться Future). - **toProvideAsync** — асинхронная фабрика (например, если нужно дожидаться Future).
- **toProvideWithParams / toProvideAsyncWithParams** — фабрики с параметрами. - **toProvideWithParams / toProvideAsyncWithParams** — фабрики с параметрами.
@@ -108,6 +110,15 @@ final api = scope.resolve<ApiClient>(named: 'mock');
- `.singleton()` — один инстанс на всё время жизни Scope. - `.singleton()` — один инстанс на всё время жизни Scope.
- По умолчанию каждый resolve создаёт новый объект. - По умолчанию каждый resolve создаёт новый объект.
> **Примечание о `.singleton()` и `.toInstance()`:**
>
> Вызов `.singleton()` после `.toInstance()` не изменяет поведения биндинга: объект, переданный через `toInstance()`, и так всегда будет "единственным" (single instance), возвращаемым при каждом resolve.
>
> Применять `.singleton()` к уже существующему объекту нет необходимости — этот вызов ничего не меняет.
>
> `.singleton()` нужен только для провайдеров (например, `toProvide`/`toProvideAsync`), чтобы зафиксировать единственный экземпляр, создаваемый фабрикой.
### Параметрические биндинги ### Параметрические биндинги
Позволяют создавать зависимости с runtime-параметрами — например, сервис для пользователя с ID: Позволяют создавать зависимости с runtime-параметрами — например, сервис для пользователя с ID: