Skip to content

Commit

Permalink
Support init properties
Browse files Browse the repository at this point in the history
  • Loading branch information
Nikolay Pyanikov committed Sep 9, 2022
1 parent 407007c commit bc5f4bc
Show file tree
Hide file tree
Showing 7 changed files with 338 additions and 64 deletions.
100 changes: 100 additions & 0 deletions Pure.DI.Tests/Integration/ErrorsAndWarningsTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
namespace Pure.DI.Tests.Integration;

using Core;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;

public class ErrorsAndWarningsTests
{
Expand Down Expand Up @@ -500,4 +502,102 @@ internal class CompositionRoot
// Then
output.Any(i => i.Contains(Diagnostics.Error.InvalidSetup)).ShouldBeTrue(generatedCode);
}

[Fact]
public void ShouldShowCompilationErrorWhenWhenBindingContainsGenericTypeMarkerOnlyAsFactory()
{
// Given

// When
var output = @"
namespace Sample
{
using System;
using Pure.DI;
static partial class Composer
{
static Composer()
{
DI.Setup()
.Bind<TT>().To(ctx => typeof(TT) == typeof(string) ? (TT)(object)""Abc"" : (TT)new object())
// Composition Root
.Bind<CompositionRoot>().To<CompositionRoot>();
}
}
internal class CompositionRoot
{
public readonly string Value;
internal CompositionRoot(string value) => Value = value.ToString();
}
}".Run(out var generatedCode);

// Then
output.ShouldBe(new[]
{
"Abc"
}, generatedCode);
}

[Fact]
public void ShouldShowCompilationErrorWhenCannotResolveProperty()
{
// Given

// When
var output = @"
#pragma warning disable CS8618
namespace Sample
{
using System;
using Pure.DI;
static partial class Composer
{
static Composer()
{
DI.Setup()
.Bind<IDependency>().To<Dependency>()
.Bind<MyService>().To<MyService>()
// Composition Root
.Bind<CompositionRoot>().To<CompositionRoot>();
}
}
internal interface IDependency
{
int Index { get; set; }
}
internal class Dependency: IDependency
{
public int Index { get; set; }
}
internal class MyService
{
[Order(0)] public IDependency Dependency { get; init; }
[Order(1)] public string State { get; init; }
}
internal class CompositionRoot
{
public readonly string Value;
internal CompositionRoot(MyService myService) => Value = myService.State + myService.Dependency.ToString();
}
#pragma warning restore CS8618
}".Run(
out var generatedCode,
new RunOptions
{
NullableContextOptions = NullableContextOptions.Annotations,
LanguageVersion = LanguageVersion.CSharp9,
Statements = string.Empty
});

// Then
output.Any(i => i.Contains(Diagnostics.Error.CannotResolve) && i.Contains("MyService.State State")).ShouldBeTrue(generatedCode);
}
}
36 changes: 30 additions & 6 deletions Pure.DI.Tests/Integration/SetupTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1870,39 +1870,63 @@ internal class CompositionRoot
}

[Fact]
public void ShouldShowCompilationErrorWhenWhenBindingContainsGenericTypeMarkerOnly()
public void ShouldSupportInitProperty()
{
// Given

// When
var output = @"
#pragma warning disable CS8618
namespace Sample
{
using System;
using Pure.DI;
static partial class Composer
{
static Composer()
{
DI.Setup()
.Bind<TT>().To(ctx => typeof(TT) == typeof(string) ? (TT)(object)""Abc"" : (TT)new object())
.Bind<IDependency>().To<Dependency>()
.Bind<MyService>().To<MyService>()
// Composition Root
.Bind<CompositionRoot>().To<CompositionRoot>();
}
}
internal interface IDependency
{
int Index { get; set; }
}
internal class Dependency: IDependency
{
public int Index { get; set; }
}
internal class MyService
{
[Order(0)] public IDependency Dependency { get; init; }
}
internal class CompositionRoot
{
public readonly string Value;
internal CompositionRoot(string value) => Value = value.ToString();
internal CompositionRoot(MyService myService) => Value = myService.Dependency.ToString();
}
}".Run(out var generatedCode);
#pragma warning restore CS8618
}".Run(
out var generatedCode,
new RunOptions
{
NullableContextOptions = NullableContextOptions.Annotations,
LanguageVersion = LanguageVersion.CSharp9
});

// Then
output.ShouldBe(new[]
{
"Abc"
"Sample.Dependency"
}, generatedCode);
}
}
2 changes: 2 additions & 0 deletions Pure.DI.UsageScenarios.Tests/DefaultFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ public void Run()
DI.Setup()
.Bind<TT>().To(ctx =>
{
// Put any logic here to create an instance of the TT type
// For example, some IoC container can be used to obtain an instance.
if (typeof(TT) == typeof(int))
{
return (TT)(object)33;
Expand Down
38 changes: 38 additions & 0 deletions Pure.DI.UsageScenarios.Tests/InitProperty.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#pragma warning disable CS8618
// ReSharper disable ClassNeverInstantiated.Global
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedMember.Global
// ReSharper disable UnusedVariable
// ReSharper disable UnusedParameter.Local
// ReSharper disable ArrangeNamespaceBody
namespace Pure.DI.UsageScenarios.Tests
{
using Xunit;

public class InitProperty
{
[Fact]
// $visible=true
// $tag=1 Basics
// $priority=07
// $description=Init property
// {
public void Run()
{
DI.Setup()
.Bind<IService>().To<MyService>()
.Bind<IDependency>().To<Dependency>();

var service = InitPropertyDI.Resolve<IService>();
}

public class MyService: IService
{
[Order(0)] public IDependency Dependency { get; init; }

public string State => "Some state";
}
// }
}
}
#pragma warning restore CS8618
27 changes: 27 additions & 0 deletions Pure.DI.UsageScenarios.Tests/README_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
- [Dependency tag](#dependency-tag)
- [Injection of default parameters](#injection-of-default-parameters)
- [Injection of nullable parameters](#injection-of-nullable-parameters)
- [Init property](#init-property)
- [Complex generics](#complex-generics)
- [Complex generics with constraints](#complex-generics-with-constraints)
- [Depends On](#depends-on)
Expand Down Expand Up @@ -586,6 +587,30 @@ public class SomeService: IService



### Init property



``` CSharp
public void Run()
{
DI.Setup()
.Bind<IService>().To<MyService>()
.Bind<IDependency>().To<Dependency>();

var service = InitPropertyDI.Resolve<IService>();
}

public class MyService: IService
{
[Order(0)] public IDependency Dependency { get; init; }

public string State => "Some state";
}
```



### Complex generics

Autowiring generic types is as easy as autowiring other simple types. Just use generic parameter markers like _TT_, _TT1_, _TT2_ etc or TTI, TTI1, TTI2... for interfaces or _TTS_, _TTS1_, _TTS2_... for value types or other special markers like _TTDisposable_ , _TTDisposable1_ , etc. _TTList <>_, _TTDictionary<>_ ... or create your own generic markers like _TTMy_ in the example below. Your own generic markers must meet 2 conditions: the type name must start with _TT_ and the type must have the _[GenericTypeArgument]_ attribute.
Expand Down Expand Up @@ -714,6 +739,8 @@ public void Run()
DI.Setup()
.Bind<TT>().To(ctx =>
{
// Put any logic here to create an instance of the TT type
// For example, some IoC container can be used to obtain an instance.
if (typeof(TT) == typeof(int))
{
return (TT)(object)33;
Expand Down
Loading

0 comments on commit bc5f4bc

Please sign in to comment.