-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
97ba14b
commit 98f41b5
Showing
29 changed files
with
518 additions
and
93 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
#### Exposed roots via arg | ||
|
||
[![CSharp](https://img.shields.io/badge/C%23-code-blue.svg)](../tests/Pure.DI.UsageTests/Advanced/ExposedRootsViaArgScenario.cs) | ||
|
||
Composition roots from other assemblies or projects can be used as a source of bindings passed through class arguments. When you add a binding to a composition from another assembly or project, the roots of the composition with the `RootKind.Exposed` type will be used in the bindings automatically. For example, in some assembly a composition is defined as: | ||
```c# | ||
public partial class CompositionInOtherProject | ||
{ | ||
private static void Setup() => | ||
DI.Setup() | ||
.Bind().As(Lifetime.Singleton).To<MyDependency>() | ||
.Bind().To<MyService>() | ||
.Root<IMyService>("MyService", kind: RootKinds.Exposed); | ||
} | ||
``` | ||
|
||
|
||
```c# | ||
interface IDependency; | ||
|
||
class Dependency : IDependency; | ||
|
||
interface IService; | ||
|
||
class Service(IDependency dependency) : IService; | ||
|
||
class Program(IService service, IMyService myService) | ||
{ | ||
public IService Service { get; } = service; | ||
|
||
public void DoSomething() => myService.DoSomething(); | ||
} | ||
|
||
DI.Setup(nameof(Composition)) | ||
.Bind<IDependency>().To<Dependency>() | ||
.Bind<IService>().To<Service>() | ||
// Binds to exposed composition roots from other project | ||
.Arg<CompositionInOtherProject>("baseComposition") | ||
.Root<Program>("Program"); | ||
|
||
var baseComposition = new CompositionInOtherProject(); | ||
var composition = new Composition(baseComposition); | ||
var program = composition.Program; | ||
program.DoSomething(); | ||
``` | ||
|
||
The following partial class will be generated: | ||
|
||
```c# | ||
partial class Composition | ||
{ | ||
private readonly Composition _root; | ||
|
||
private readonly Integration.CompositionInOtherProject _argBaseComposition; | ||
|
||
[OrdinalAttribute(10)] | ||
public Composition(Integration.CompositionInOtherProject baseComposition) | ||
{ | ||
_argBaseComposition = baseComposition ?? throw new ArgumentNullException(nameof(baseComposition)); | ||
_root = this; | ||
} | ||
|
||
internal Composition(Composition parentScope) | ||
{ | ||
_root = (parentScope ?? throw new ArgumentNullException(nameof(parentScope)))._root; | ||
_argBaseComposition = _root._argBaseComposition; | ||
} | ||
|
||
public Program Program | ||
{ | ||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
get | ||
{ | ||
Integration.IMyService transientIMyService2; | ||
{ | ||
Integration.CompositionInOtherProject localValue4 = _argBaseComposition; | ||
transientIMyService2 = localValue4.MyService; | ||
} | ||
|
||
return new Program(new Service(new Dependency()), transientIMyService2); | ||
} | ||
} | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public T Resolve<T>() | ||
{ | ||
return Resolver<T>.Value.Resolve(this); | ||
} | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public T Resolve<T>(object? tag) | ||
{ | ||
return Resolver<T>.Value.ResolveByTag(this, tag); | ||
} | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public object Resolve(Type type) | ||
{ | ||
var index = (int)(_bucketSize * ((uint)RuntimeHelpers.GetHashCode(type) % 1)); | ||
ref var pair = ref _buckets[index]; | ||
return pair.Key == type ? pair.Value.Resolve(this) : Resolve(type, index); | ||
} | ||
|
||
[MethodImpl(MethodImplOptions.NoInlining)] | ||
private object Resolve(Type type, int index) | ||
{ | ||
var finish = index + _bucketSize; | ||
while (++index < finish) | ||
{ | ||
ref var pair = ref _buckets[index]; | ||
if (pair.Key == type) | ||
{ | ||
return pair.Value.Resolve(this); | ||
} | ||
} | ||
|
||
throw new InvalidOperationException($"{CannotResolveMessage} {OfTypeMessage} {type}."); | ||
} | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public object Resolve(Type type, object? tag) | ||
{ | ||
var index = (int)(_bucketSize * ((uint)RuntimeHelpers.GetHashCode(type) % 1)); | ||
ref var pair = ref _buckets[index]; | ||
return pair.Key == type ? pair.Value.ResolveByTag(this, tag) : Resolve(type, tag, index); | ||
} | ||
|
||
[MethodImpl(MethodImplOptions.NoInlining)] | ||
private object Resolve(Type type, object? tag, int index) | ||
{ | ||
var finish = index + _bucketSize; | ||
while (++index < finish) | ||
{ | ||
ref var pair = ref _buckets[index]; | ||
if (pair.Key == type) | ||
{ | ||
return pair.Value.ResolveByTag(this, tag); | ||
} | ||
} | ||
|
||
throw new InvalidOperationException($"{CannotResolveMessage} \"{tag}\" {OfTypeMessage} {type}."); | ||
} | ||
|
||
private readonly static int _bucketSize; | ||
private readonly static Pair<Type, IResolver<Composition, object>>[] _buckets; | ||
|
||
static Composition() | ||
{ | ||
var valResolver_0000 = new Resolver_0000(); | ||
Resolver<Program>.Value = valResolver_0000; | ||
_buckets = Buckets<Type, IResolver<Composition, object>>.Create( | ||
1, | ||
out _bucketSize, | ||
new Pair<Type, IResolver<Composition, object>>[1] | ||
{ | ||
new Pair<Type, IResolver<Composition, object>>(typeof(Program), valResolver_0000) | ||
}); | ||
} | ||
|
||
private const string CannotResolveMessage = "Cannot resolve composition root "; | ||
private const string OfTypeMessage = "of type "; | ||
|
||
private class Resolver<T>: IResolver<Composition, T> | ||
{ | ||
public static IResolver<Composition, T> Value = new Resolver<T>(); | ||
|
||
public virtual T Resolve(Composition composite) | ||
{ | ||
throw new InvalidOperationException($"{CannotResolveMessage}{OfTypeMessage}{typeof(T)}."); | ||
} | ||
|
||
public virtual T ResolveByTag(Composition composite, object tag) | ||
{ | ||
throw new InvalidOperationException($"{CannotResolveMessage}\"{tag}\" {OfTypeMessage}{typeof(T)}."); | ||
} | ||
} | ||
|
||
private sealed class Resolver_0000: Resolver<Program> | ||
{ | ||
public override Program Resolve(Composition composition) | ||
{ | ||
return composition.Program; | ||
} | ||
|
||
public override Program ResolveByTag(Composition composition, object tag) | ||
{ | ||
switch (tag) | ||
{ | ||
case null: | ||
return composition.Program; | ||
|
||
default: | ||
return base.ResolveByTag(composition, tag); | ||
} | ||
} | ||
} | ||
} | ||
``` | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
#### Exposed roots via root arg | ||
|
||
[![CSharp](https://img.shields.io/badge/C%23-code-blue.svg)](../tests/Pure.DI.UsageTests/Advanced/ExposedRootsViaRootArgScenario.cs) | ||
|
||
Composition roots from other assemblies or projects can be used as a source of bindings passed through root arguments. When you add a binding to a composition from another assembly or project, the roots of the composition with the `RootKind.Exposed` type will be used in the bindings automatically. For example, in some assembly a composition is defined as: | ||
```c# | ||
public partial class CompositionInOtherProject | ||
{ | ||
private static void Setup() => | ||
DI.Setup() | ||
.Bind().As(Lifetime.Singleton).To<MyDependency>() | ||
.Bind().To<MyService>() | ||
.Root<IMyService>("MyService", kind: RootKinds.Exposed); | ||
} | ||
``` | ||
|
||
|
||
```c# | ||
interface IDependency; | ||
|
||
class Dependency : IDependency; | ||
|
||
interface IService; | ||
|
||
class Service(IDependency dependency) : IService; | ||
|
||
class Program(IService service, IMyService myService) | ||
{ | ||
public IService Service { get; } = service; | ||
|
||
public void DoSomething() => myService.DoSomething(); | ||
} | ||
|
||
DI.Setup(nameof(Composition)) | ||
.Hint(Hint.Resolve, "Off") | ||
.Bind<IDependency>().To<Dependency>() | ||
.Bind<IService>().To<Service>() | ||
// Binds to exposed composition roots from other project | ||
.RootArg<CompositionInOtherProject>("baseComposition") | ||
.Root<Program>("GetProgram"); | ||
|
||
var baseComposition = new CompositionInOtherProject(); | ||
var composition = new Composition(); | ||
var program = composition.GetProgram(baseComposition); | ||
program.DoSomething(); | ||
``` | ||
|
||
The following partial class will be generated: | ||
|
||
```c# | ||
partial class Composition | ||
{ | ||
private readonly Composition _root; | ||
|
||
[OrdinalAttribute(10)] | ||
public Composition() | ||
{ | ||
_root = this; | ||
} | ||
|
||
internal Composition(Composition parentScope) | ||
{ | ||
_root = (parentScope ?? throw new ArgumentNullException(nameof(parentScope)))._root; | ||
} | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public Program GetProgram(Integration.CompositionInOtherProject baseComposition) | ||
{ | ||
Integration.IMyService transientIMyService2; | ||
{ | ||
Integration.CompositionInOtherProject localValue5 = baseComposition; | ||
transientIMyService2 = localValue5.MyService; | ||
} | ||
|
||
return new Program(new Service(new Dependency()), transientIMyService2); | ||
} | ||
} | ||
``` | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.