Skip to content

Commit 2e2fa8e

Browse files
authored
Merge pull request #100 from KuraiAndras/feature/add-inhertiance-injection
9.1.0
2 parents b6eebfa + 42e0a7b commit 2e2fa8e

File tree

9 files changed

+105
-13
lines changed

9 files changed

+105
-13
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# 9.1.0
2+
- Add `MonoBheaviourInjected` again with new implementation. Extend docs accordingly
3+
14
# 9.0.2
25
- Fix override handling when running the editor tool
36

Documentation/documentation/injecter.unity.md

+41-8
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,13 @@ The `Injecter.Unity` lets you set up the following flow:
1414

1515
- A "composition root" is initialized part of the entry point of the application
1616
- Create a script which needs to be injected
17-
- Add `MonoInjector` to the `GameObject` hosting the script
18-
- `MonoInjector` runs at `Awake`, and it's execution order (`int.MinValue` - first) is run before your own component's `Awake`. Every injected script will have it's own `IServiceScope` derived from the root scope. This scope can be retrieved through the `IScopeStore`, and the owner of the scope is the script being injected
19-
- When the `GameObject` is destroyed, `MonoDisposer` will run during the `OnDestroy` method, with an execution order of `int.MaxValue` - last
17+
- Choose an injection method:
18+
- Either use the helper components
19+
- Add `MonoInjector` to the `GameObject` hosting the script
20+
- `MonoInjector` runs at `Awake`, and it's execution order (`int.MinValue` - first) is run before your own component's `Awake`. Every injected script will have it's own `IServiceScope` derived from the root scope. This scope can be retrieved through the `IScopeStore`, and the owner of the scope is the script being injected
21+
- When the `GameObject` is destroyed, `MonoDisposer` will run during the `OnDestroy` method, with an execution order of `int.MaxValue` - last
22+
- Or derive from `MonoBehaviourInjecter`
23+
- The base class `Awake` method will do the injections, and the `OnDestroy` method will dispose of the scope
2024

2125
## Getting started
2226

@@ -80,7 +84,9 @@ public static class AppInstaller
8084
}
8185
```
8286

83-
### Inject into `MonoBehaviours`
87+
### Inject using the helper components
88+
89+
#### Inject into `MonoBehaviours`
8490

8591
Create a script which will receive injection
8692

@@ -92,16 +98,40 @@ public class MyScript : MonoBehaviour
9298
}
9399
```
94100

95-
### Add `MonoInjector`
101+
#### Add `MonoInjector`
96102

97103
If you decorate your script with `[RequireComponent(typeof(MonoInjector))]` then, when adding the script to a `GameObject` the editor will add the `MonoInjector` and the `MonoDisposer` script to your `GameObject`. If for some reason this does not happen (for example, when changing an already living script into one needing injection), either add the `MonoInjector` component manually, or use the editor tools included to add the missing components to scenes or prefabs (will search all instances) through the editor menu `Tools / Injecter / ...`
98104

105+
### Inject by inheriting from `MonoBehaviourInjected`
106+
107+
Create a script which will receive injection
108+
109+
```csharp
110+
public class MyScript : MonoBehaviourInjected
111+
{
112+
[Inject] private readonly IMyService _service = default!;
113+
114+
protected override void Awake()
115+
{
116+
base.Awake();
117+
118+
// Custom logic goes here
119+
}
120+
121+
protected override void OnDestroy()
122+
{
123+
// Custom cleanup logic goes herer
124+
125+
base.OnDestroy();
126+
}
127+
}
128+
```
129+
99130
## Manual injection
100131

101132
When dynamically adding an injectable script to a `GameObject`, you should **not** annotate the injected script with the `RequireComponent` attribute, and add the `MonoInjector` manually, like so:
102133

103134
```csharp
104-
105135
var myObject = new GameObject("MyObject");
106136
myObject.AddComponent<TestComponent>();
107137
myObject.AddComponent<MonoInjector>();
@@ -110,7 +140,6 @@ public class MyComponent : MonoBehaviour
110140
{
111141
[Inject] private readonly MyService _service = default!;
112142
}
113-
114143
```
115144

116145
## Testing
@@ -157,7 +186,11 @@ public IEnumerator My_Test_Does_Stuff()
157186
> [!NOTE]
158187
> You can also do the same in the test's `Setup` or `Teardown` stage
159188
160-
## Migrating from `8.0.1` to `9.0.0`
189+
## Migrating from `8.0.1` to `9.0.0` and above
190+
191+
If you want to continue using the inheritance setup, then change all base classes to be `MonoBehaviourInjected`. The new base class will always create scopes.
192+
193+
If you want to migrate to the component-based injection:
161194

162195
1. Set up a composition root as described above.
163196
2. Remove inheriting from the old `MonoBehaviourInjected` and similar classes

MainProject/Directory.Build.props

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<LangVersion>9.0</LangVersion>
44
<Nullable>enable</Nullable>
55

6-
<CurrentVersion>9.0.2</CurrentVersion>
6+
<CurrentVersion>9.1.0</CurrentVersion>
77

88
<Version>$(CurrentVersion)</Version>
99
<PakcageVersion>$(CurrentVersion)</PakcageVersion>

UnityProject/Injecter.Unity/Assets/Injecter.Hosting.Unity/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "com.injecter.hosting.unity",
3-
"version": "9.0.2",
3+
"version": "9.1.0",
44
"displayName": "Injecter.Hosting.Unity",
55
"license": "MIT",
66
"licensesUrl": "https://github.com/KuraiAndras/Injecter/blob/master/LICENSE.md",

UnityProject/Injecter.Unity/Assets/Injecter.Unity/Editor/MonoInjecterFinder.cs

+10-2
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,16 @@ private static bool CanBeInjected(MonoBehaviour component)
3535

3636
if (!_typeCache.TryGetValue(type, out var isInjectable))
3737
{
38-
var members = TypeHelpers.GetInjectableMembers(type);
39-
isInjectable = members.Count != 0;
38+
if (type.IsSubclassOf(typeof(MonoBehaviourInjected)))
39+
{
40+
isInjectable = false;
41+
}
42+
else
43+
{
44+
var members = TypeHelpers.GetInjectableMembers(type);
45+
isInjectable = members.Count != 0;
46+
}
47+
4048
_typeCache.Add(type, isInjectable);
4149
}
4250

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using Microsoft.Extensions.DependencyInjection;
2+
using UnityEngine;
3+
4+
namespace Injecter.Unity
5+
{
6+
/// <summary>
7+
/// Inheriting from this class will inject everything marked with the <see cref="InjectAttribute"/>
8+
/// </summary>
9+
public abstract class MonoBehaviourInjected : MonoBehaviour
10+
{
11+
[Inject] private IScopeStore _store;
12+
13+
protected IServiceScope Scope { get; private set; }
14+
15+
/// <summary>
16+
/// Call the base function before accessing injected members
17+
/// </summary>
18+
[System.Diagnostics.CodeAnalysis.SuppressMessage("Roslynator", "RCS1213:Remove unused member declaration.", Justification = "Unity method")]
19+
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0079:Remove unnecessary suppression", Justification = "Unity method")]
20+
protected virtual void Awake() => Scope = CompositionRoot.ServiceProvider.GetRequiredService<IInjecter>().InjectIntoType(this, true);
21+
22+
/// <summary>
23+
/// Call the base function after accessing injected members
24+
/// </summary>
25+
[System.Diagnostics.CodeAnalysis.SuppressMessage("Roslynator", "RCS1213:Remove unused member declaration.", Justification = "Unity method")]
26+
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0079:Remove unnecessary suppression", Justification = "Unity method")]
27+
protected virtual void OnDestroy()
28+
{
29+
_store.DisposeScope(this);
30+
31+
Scope = null;
32+
_store = null;
33+
}
34+
}
35+
}

UnityProject/Injecter.Unity/Assets/Injecter.Unity/MonoBehaviourInjected.cs.meta

+11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

UnityProject/Injecter.Unity/Assets/Injecter.Unity/MonoInjector.cs

+2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ private void Awake()
2626
var component = components[i];
2727
if (component == null || component == this) continue;
2828

29+
if (component.GetType().IsSubclassOf(typeof(MonoBehaviourInjected))) continue;
30+
2931
injecter.InjectIntoType(component, true);
3032
owners.Add(component);
3133
}

UnityProject/Injecter.Unity/Assets/Injecter.Unity/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "com.injecter.unity",
3-
"version": "9.0.2",
3+
"version": "9.1.0",
44
"displayName": "Injecter.Unity",
55
"license": "MIT",
66
"licensesUrl": "https://github.com/KuraiAndras/Injecter/blob/master/LICENSE.md",

0 commit comments

Comments
 (0)