Skip to content

Commit

Permalink
Update README.md
Browse files Browse the repository at this point in the history
  • Loading branch information
NikolayPianikov committed May 14, 2024
1 parent 2186f21 commit c7cd323
Show file tree
Hide file tree
Showing 34 changed files with 234 additions and 758 deletions.
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ dotnet run
- [Resolve methods](readme/resolve-methods.md)
- [Simplified binding](readme/simplified-binding.md)
- [Factory](readme/factory.md)
- [Arguments](readme/arguments.md)
- [Class arguments](readme/class-arguments.md)
- [Root arguments](readme/root-arguments.md)
- [Tags](readme/tags.md)
- [Field injection](readme/field-injection.md)
Expand All @@ -209,16 +209,16 @@ dotnet run
- [Required properties or fields](readme/required-properties-or-fields.md)
- [Root binding](readme/root-binding.md)
### Lifetimes
- [Transient](readme/transient.md)
- [Singleton](readme/singleton.md)
- [PerResolve](readme/perresolve.md)
- [Scope](readme/scope.md)
- [PerBlock](readme/perblock.md)
- [Transient](readme/transient.md)
- [Disposable singleton](readme/disposable-singleton.md)
- [Async disposable scope](readme/async-disposable-scope.md)
- [Async disposable singleton](readme/async-disposable-singleton.md)
- [Scope](readme/scope.md)
- [Auto scoped](readme/auto-scoped.md)
- [Default lifetime](readme/default-lifetime.md)
- [Disposable singleton](readme/disposable-singleton.md)
- [Async disposable singleton](readme/async-disposable-singleton.md)
- [Async disposable scope](readme/async-disposable-scope.md)
### Base Class Library
- [Func](readme/func.md)
- [Enumerable](readme/enumerable.md)
Expand Down
37 changes: 25 additions & 12 deletions readme/arguments.md → readme/class-arguments.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#### Arguments
#### Class arguments

[![CSharp](https://img.shields.io/badge/C%23-code-blue.svg)](../tests/Pure.DI.UsageTests/Basics/ArgumentsScenario.cs)
[![CSharp](https://img.shields.io/badge/C%23-code-blue.svg)](../tests/Pure.DI.UsageTests/Basics/ClassArgumentsScenario.cs)

Sometimes you need to pass some state to a composition class to use it when resolving dependencies. To do this, just use the `Arg<T>(string argName)` method, specify the type of argument and its name. You can also specify a tag for each argument. You can then use them as dependencies when building the object graph. If you have multiple arguments of the same type, just use tags to distinguish them. The values of the arguments are manipulated when you create a composition class by calling its constructor. It is important to remember that only those arguments that are used in the object graph will appear in the constructor. Arguments that are not involved will not be added to the constructor arguments.

Expand All @@ -9,11 +9,15 @@ Sometimes you need to pass some state to a composition class to use it when reso
interface IDependency
{
int Id { get; }

string Name { get; }
}

class Dependency(int id) : IDependency
class Dependency(int id, string name) : IDependency
{
public int Id { get; } = id;

public string Name { get; } = name;
}

interface IService
Expand All @@ -24,7 +28,9 @@ interface IService
}

class Service(
[Tag("name")] string name,
// The tag allows to specify the injection point accurately.
// This is useful, for example, when the type is the same.
[Tag("my service name")] string name,
IDependency dependency) : IService
{
public string Name { get; } = name;
Expand All @@ -42,17 +48,20 @@ DI.Setup(nameof(Composition))
// Some kind of identifier
.Arg<int>("id")

// An argument can be tagged (e.g., tag "name")
// An argument can be tagged (e.g., tag "my service name")
// to be injectable by type and this tag
.Arg<string>("serviceName", "name");
.Arg<string>("serviceName", "my service name")

.Arg<string>("dependencyName");

var composition = new Composition(serviceName: "Abc", id: 123);
var composition = new Composition(id: 123, serviceName: "Abc", dependencyName: "Xyz");

// service = new Service("Abc", new Dependency(123));
// service = new Service("Abc", new Dependency(123, "Xyz"));
var service = composition.Root;

service.Name.ShouldBe("Abc");
service.Dependency.Id.ShouldBe(123);
service.Dependency.Name.ShouldBe("Xyz");
```

The following partial class will be generated:
Expand All @@ -64,11 +73,13 @@ partial class Composition

private readonly int _arg_id;
private readonly string _arg_serviceName;
private readonly string _arg_dependencyName;

public Composition(int id, string serviceName)
public Composition(int id, string serviceName, string dependencyName)
{
_arg_id = id;
_arg_serviceName = serviceName ?? throw new ArgumentNullException(nameof(serviceName));
_arg_dependencyName = dependencyName ?? throw new ArgumentNullException(nameof(dependencyName));
_root = this;
}

Expand All @@ -77,14 +88,15 @@ partial class Composition
_root = (parentScope ?? throw new ArgumentNullException(nameof(parentScope)))._root;
_arg_id = _root._arg_id;
_arg_serviceName = _root._arg_serviceName;
_arg_dependencyName = _root._arg_dependencyName;
}

public IService Root
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return new Service(_arg_serviceName, new Dependency(_arg_id));
return new Service(_arg_serviceName, new Dependency(_arg_id, _arg_dependencyName));
}
}
}
Expand All @@ -102,7 +114,7 @@ classDiagram
class String
Dependency --|> IDependency
class Dependency {
+Dependency(Int32 id)
+Dependency(Int32 id, String name)
}
Service --|> IService
class Service {
Expand All @@ -115,7 +127,8 @@ classDiagram
<<interface>>
}
Dependency o-- Int32 : Argument "id"
Service o-- String : "name" Argument "serviceName"
Dependency o-- String : Argument "dependencyName"
Service o-- String : "my service name" Argument "serviceName"
Service *-- Dependency : IDependency
Composition ..> Service : IService Root
```
Expand Down
118 changes: 0 additions & 118 deletions readme/constructor-ordinal-attribute.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,120 +74,6 @@ partial class Composition
return new Service(_arg_serviceName);
}
}

[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<IService>.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(IService), 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<IService>
{
public override IService Resolve(Composition composition)
{
return composition.Root;
}

public override IService ResolveByTag(Composition composition, object tag)
{
switch (tag)
{
case null:
return composition.Root;

default:
return base.ResolveByTag(composition, tag);
}
}
}
}
```

Expand All @@ -198,10 +84,6 @@ classDiagram
class Composition {
<<partial>>
+IService Root
+ T ResolveᐸTᐳ()
+ T ResolveᐸTᐳ(object? tag)
+ object Resolve(Type type)
+ object Resolve(Type type, object? tag)
}
class String
Service --|> IService
Expand Down
Loading

0 comments on commit c7cd323

Please sign in to comment.