Skip to content

Commit

Permalink
Bind attr
Browse files Browse the repository at this point in the history
  • Loading branch information
NikolayPianikov committed Jul 30, 2024
1 parent 97ba14b commit 98f41b5
Show file tree
Hide file tree
Showing 29 changed files with 518 additions and 93 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,8 @@ dotnet run
- [Tracking async disposable instances in delegates](readme/tracking-async-disposable-instances-in-delegates.md)
- [Exposed roots](readme/exposed-roots.md)
- [Exposed roots with tags](readme/exposed-roots-with-tags.md)
- [Exposed roots via arg](readme/exposed-roots-via-arg.md)
- [Exposed roots via root arg](readme/exposed-roots-via-root-arg.md)
- [Exposed generic roots](readme/exposed-generic-roots.md)
- [Exposed generic roots it args](readme/exposed-generic-roots-it-args.md)
### Applications
Expand Down
4 changes: 2 additions & 2 deletions readme/async-disposable-scope.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,8 @@ partial class Composition: IDisposable, IAsyncDisposable
() =>
{
Composition transientComposition2 = this;
Session localValue56 = new Session(transientComposition2);
return localValue56;
Session localValue58 = new Session(transientComposition2);
return localValue58;
});
}
}
Expand Down
20 changes: 10 additions & 10 deletions readme/async-root.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,11 @@ partial class Composition
TaskCreationOptions transientTaskCreationOptions2 = TaskCreationOptions.None;
TaskFactory<IService> perBlockTaskFactory1;
{
CancellationToken localCancellationToken15 = cancellationToken;
TaskCreationOptions localTaskCreationOptions16 = transientTaskCreationOptions2;
TaskContinuationOptions localTaskContinuationOptions17 = transientTaskContinuationOptions3;
TaskScheduler localTaskScheduler18 = transientTaskScheduler4;
perBlockTaskFactory1 = new TaskFactory<IService>(localCancellationToken15, localTaskCreationOptions16, localTaskContinuationOptions17, localTaskScheduler18);
CancellationToken localCancellationToken17 = cancellationToken;
TaskCreationOptions localTaskCreationOptions18 = transientTaskCreationOptions2;
TaskContinuationOptions localTaskContinuationOptions19 = transientTaskContinuationOptions3;
TaskScheduler localTaskScheduler20 = transientTaskScheduler4;
perBlockTaskFactory1 = new TaskFactory<IService>(localCancellationToken17, localTaskCreationOptions18, localTaskContinuationOptions19, localTaskScheduler20);
}

if (perResolveFunc45 == null)
Expand All @@ -76,18 +76,18 @@ partial class Composition
[MethodImpl(MethodImplOptions.AggressiveInlining)]
() =>
{
IService localValue19 = new Service(new Dependency());
return localValue19;
IService localValue21 = new Service(new Dependency());
return localValue21;
});
}
}
}

Task<IService> transientTask0;
{
Func<IService> localFactory20 = perResolveFunc45!;
TaskFactory<IService> localTaskFactory21 = perBlockTaskFactory1;
transientTask0 = localTaskFactory21.StartNew(localFactory20);
Func<IService> localFactory22 = perResolveFunc45!;
TaskFactory<IService> localTaskFactory23 = perBlockTaskFactory1;
transientTask0 = localTaskFactory23.StartNew(localFactory22);
}

return transientTask0;
Expand Down
10 changes: 5 additions & 5 deletions readme/auto-scoped.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,14 +109,14 @@ partial class Composition
Composition transientComposition2 = this;
IService transientIService1;
{
Composition localBaseComposition58 = transientComposition2;
Composition localBaseComposition60 = transientComposition2;
// Creates a session
var localSession59 = new Composition(localBaseComposition58);
transientIService1 = localSession59.SessionRoot;
var localSession61 = new Composition(localBaseComposition60);
transientIService1 = localSession61.SessionRoot;
}

IService localValue57 = transientIService1;
return localValue57;
IService localValue59 = transientIService1;
return localValue59;
});
}
}
Expand Down
3 changes: 3 additions & 0 deletions readme/exposed-generic-roots.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ var program = composition.Program;
program.DoSomething(99);
```

> [!IMPORTANT]
> At this point, a composition from another assembly or another project can be used for this purpose. Compositions from the current project cannot be used in this way due to limitations of the source code generators.
The following partial class will be generated:

```c#
Expand Down
200 changes: 200 additions & 0 deletions readme/exposed-roots-via-arg.md
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);
}
}
}
}
```


80 changes: 80 additions & 0 deletions readme/exposed-roots-via-root-arg.md
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);
}
}
```


4 changes: 2 additions & 2 deletions readme/exposed-roots-with-tags.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ partial class Composition

Integration.IMyService transientIMyService2;
{
Integration.CompositionWithTagsInOtherProject localValue4 = _root._singletonCompositionWithTagsInOtherProject41!;
transientIMyService2 = localValue4.MyService;
Integration.CompositionWithTagsInOtherProject localValue6 = _root._singletonCompositionWithTagsInOtherProject41!;
transientIMyService2 = localValue6.MyService;
}

return new Program(new Service(new Dependency()), transientIMyService2);
Expand Down
3 changes: 3 additions & 0 deletions readme/exposed-roots.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ var program = composition.Program;
program.DoSomething();
```

> [!IMPORTANT]
> At this point, a composition from another assembly or another project can be used for this purpose. Compositions from the current project cannot be used in this way due to limitations of the source code generators.
The following partial class will be generated:

```c#
Expand Down
Loading

0 comments on commit 98f41b5

Please sign in to comment.