@@ -9435,6 +9435,62 @@ public static void RegisterMapping<TService, TRegisteredService>(this IContainer
9435
9435
IfAlreadyRegistered ifAlreadyRegistered, object serviceKey = null, object registeredServiceKey = null) =>
9436
9436
Registrator.RegisterMapping(container,
9437
9437
typeof(TService), typeof(TRegisteredService), ifAlreadyRegistered, serviceKey, registeredServiceKey);
9438
+
9439
+ /// <summary>Returns the number of the actual registrations made.</summary>
9440
+ public static int RegisterByRegisterAttributes(this IRegistrator registrator, Type registrationAttributesTarget)
9441
+ {
9442
+ var attrs = registrationAttributesTarget.GetCustomAttributes<RegisterAttribute>(inherit: true);
9443
+ var regCount = 0;
9444
+ foreach (var attr in attrs)
9445
+ {
9446
+ var factory = CreateFactory(attr);
9447
+
9448
+ registrator.Register(factory, attr.ServiceType, attr.ServiceKey, attr.IfAlreadyRegistered,
9449
+ isStaticallyChecked: attr.TypesAreStaticallyChecked);
9450
+
9451
+ ++regCount;
9452
+ }
9453
+ return regCount;
9454
+ }
9455
+
9456
+ internal static ReflectionFactory CreateFactory(RegisterAttribute attr)
9457
+ {
9458
+ var reuse = GetReuse(attr);
9459
+ var made = Made.Default; // todo: @wip add features later
9460
+ var setup = GetSetup(attr);
9461
+ return ReflectionFactory.Of(attr.ImplementationType, reuse, made, setup);
9462
+ }
9463
+
9464
+ internal static IReuse GetReuse(RegisterAttribute attr) =>
9465
+ attr.ReuseType switch
9466
+ {
9467
+ var t when t == typeof(TransientReuse) => Reuse.Transient,
9468
+ var t when t == typeof(SingletonReuse) => Reuse.Singleton,
9469
+ var t when t == typeof(CurrentScopeReuse) =>
9470
+ attr.ReuseScopeName == null & attr.ReuseScopeNames == null ? Reuse.Scoped :
9471
+ attr.ReuseScopeName != null ? Reuse.ScopedTo(attr.ReuseScopeName) : Reuse.ScopedTo(attr.ReuseScopeNames),
9472
+ // todo: @wip support this stuff later
9473
+ // ScopedToServiceType;
9474
+ // ScopedToServiceKey;
9475
+ // ScopedOrSingleton;
9476
+ var t => Throw.For<IReuse>(Error.RegisterAttributedUnsupportedReuseType, t)
9477
+ };
9478
+
9479
+ internal static Setup GetSetup(RegisterAttribute attr)
9480
+ {
9481
+ // todo: @wip support other stuff later
9482
+ var transientTracking = attr.TrackDisposableTransient;
9483
+ if (transientTracking == DisposableTracking.TrackDisposableTransient)
9484
+ return Setup.With(trackDisposableTransient: true);
9485
+
9486
+ if (transientTracking == DisposableTracking.AllowDisposableTransient)
9487
+ return Setup.With(allowDisposableTransient: true);
9488
+
9489
+ if (transientTracking == DisposableTracking.ThrowOnRegisteringDisposableTransient)
9490
+ return Setup.With(allowDisposableTransient: false);
9491
+
9492
+ return Setup.Default;
9493
+ }
9438
9494
}
9439
9495
9440
9496
/// <summary>Extension methods for <see cref="IResolver"/>.</summary>
@@ -14573,6 +14629,33 @@ public interface IReuse : IConvertibleToExpression
14573
14629
Expression Apply(Request request, Expression serviceFactoryExpr);
14574
14630
}
14575
14631
14632
+ /// <summary>Transient reuse</summary>
14633
+ public sealed class TransientReuse : IReuse
14634
+ {
14635
+ /// <inheritdoc />
14636
+ public int Lifespan => 0;
14637
+
14638
+ /// <inheritdoc />
14639
+ public object Name => null;
14640
+
14641
+ /// <inheritdoc />
14642
+ public Expression Apply(Request _, Expression serviceFactoryExpr) => serviceFactoryExpr;
14643
+
14644
+ /// <inheritdoc />
14645
+ public bool CanApply(Request request) => true;
14646
+
14647
+ private readonly Lazy<Expression> _transientReuseExpr = Lazy.Of<Expression>(() =>
14648
+ Field(null, typeof(Reuse).GetField(nameof(Reuse.Transient))));
14649
+
14650
+ /// <inheritdoc />
14651
+ public Expression ToExpression<S>(S state, Func<S, object, Expression> fallbackConverter) =>
14652
+ _transientReuseExpr.Value;
14653
+
14654
+ /// <inheritdoc />
14655
+ public override string ToString() => "TransientReuse";
14656
+ }
14657
+
14658
+
14576
14659
/// <summary>Returns container bound scope for storing singleton objects.</summary>
14577
14660
public sealed class SingletonReuse : IReuse
14578
14661
{
@@ -15112,30 +15195,9 @@ public static IReuse ScopedToService<TService>(object serviceKey = null) =>
15112
15195
/// <summary>Obsolete: please prefer using `Scoped` without name instead.
15113
15196
/// The usage of the named scopes is the less performant than the unnamed ones. e.g. ASP.NET Core does not use the named scope.</summary>
15114
15197
public static readonly IReuse InWebRequest = ScopedTo(WebRequestScopeName);
15198
+ }
15115
15199
15116
- #region Implementation
15117
-
15118
- private sealed class TransientReuse : IReuse
15119
- {
15120
- public int Lifespan => 0;
15121
-
15122
- public object Name => null;
15123
-
15124
- public Expression Apply(Request _, Expression serviceFactoryExpr) => serviceFactoryExpr;
15125
-
15126
- public bool CanApply(Request request) => true;
15127
-
15128
- private readonly Lazy<Expression> _transientReuseExpr = Lazy.Of<Expression>(() =>
15129
- Field(null, typeof(Reuse).GetField(nameof(Transient))));
15130
-
15131
- public Expression ToExpression<S>(S state, Func<S, object, Expression> fallbackConverter) =>
15132
- _transientReuseExpr.Value;
15133
15200
15134
- public override string ToString() => "TransientReuse";
15135
- }
15136
-
15137
- #endregion
15138
- }
15139
15201
15140
15202
/// <summary>Policy to handle unresolved service.</summary>
15141
15203
public enum IfUnresolved : byte
@@ -15871,7 +15933,8 @@ public static readonly int
15871
15933
"service creation is failed with the exception and the exception was catched, but you're trying to resolve the failed service again. " + NewLine +
15872
15934
"For all those reasons DryIoc has a timeout to prevent the infinite waiting. " + NewLine +
15873
15935
$"You may change the default timeout via setting the static `Scope.{nameof(Scope.WaitForScopedServiceIsCreatedTimeoutMilliseconds)}`"),
15874
- ServiceTypeIsNull = Of("Registered service type is null");
15936
+ ServiceTypeIsNull = Of("Registered service type is null"),
15937
+ RegisterAttributedUnsupportedReuseType = Of("Not support reuse type {0} in the RegisterAttribute.");
15875
15938
15876
15939
#pragma warning restore 1591 // "Missing XML-comment"
15877
15940
@@ -16691,15 +16754,75 @@ public class CompileTimeRegisterAttribute : Attribute
16691
16754
{
16692
16755
}
16693
16756
16694
- [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
16695
- internal class RegisterAttribute : Attribute // todo: @wip make it public
16757
+ /// <summary>Per-registration rules to handle the disposable transient</summary>
16758
+ public enum DisposableTracking : byte
16759
+ {
16760
+ /// <summary>Default behavior is to obey the container rules</summary>
16761
+ UseContainerRules = 0,
16762
+ /// <summary>Throws the Container exception when trying to register a disposable transient, overriding the container rules</summary>
16763
+ ThrowOnRegisteringDisposableTransient,
16764
+ /// <summary>Allow registering the disposable transient</summary>
16765
+ AllowDisposableTransient,
16766
+ /// <summary>Track disposable transient</summary>
16767
+ TrackDisposableTransient
16768
+ }
16769
+
16770
+ /// <summary>Base registration attribute,
16771
+ /// there may be descendant predefined and custom attributes simplifying the registration setup.</summary>
16772
+ public class RegisterAttribute : Attribute
16696
16773
{
16697
- // public Type ServiceType;
16774
+ /// <summary>By default no, because the attribute operates on the</summary>
16775
+ public virtual bool TypesAreStaticallyChecked => false;
16698
16776
16699
- // todo: @feature @wip implement the Register in the attribute
16700
- // void Register(Factory factory, Type serviceType, object serviceKey, IfAlreadyRegistered? ifAlreadyRegistered, bool isStaticallyChecked);
16701
- // public static ReflectionFactory Of(Type implementationType = null, IReuse reuse = null, Made made = null, Setup setup = null)
16702
- // todo: add RegisterMany
16777
+ /// <summary>A service type</summary>
16778
+ public Type ServiceType;
16779
+
16780
+ /// <summary>An implementation type</summary>
16781
+ public Type ImplementationType;
16782
+
16783
+ /// <summary>One of the IReuse implementation types.</summary>
16784
+ public Type ReuseType; // todo: @wip change to the ScopeType, move it from the AttributedModel
16785
+
16786
+ /// <summary>Optional name of the bound scope for the Scoped reuse</summary>
16787
+ public string ReuseScopeName;
16788
+
16789
+ /// <summary>Optional names of the bound scopes fore the Scoped reuse. Maybe overridden by <see cref="ReuseScopeName"/></summary>
16790
+ public object[] ReuseScopeNames;
16791
+
16792
+ public Type ScopedToServiceType;
16793
+ public Type ScopedToServiceKey;
16794
+ public bool ScopedOrSingleton;
16795
+
16796
+ /// <summary>A service key</summary>
16797
+ public object ServiceKey;
16798
+
16799
+ /// <summary>Uses the global container rules by default</summary>
16800
+ public IfAlreadyRegistered? IfAlreadyRegistered;
16801
+
16802
+ // public Made Made;
16803
+
16804
+ /// <summary>How to track the disposable transient</summary>
16805
+ public DisposableTracking TrackDisposableTransient;
16806
+ }
16807
+
16808
+ // todo: @feature @wip implement the Register in the attribute
16809
+ // void Register(Factory factory, Type serviceType, object serviceKey, IfAlreadyRegistered? ifAlreadyRegistered, bool isStaticallyChecked);
16810
+ // public static ReflectionFactory Of(Type implementationType = null, IReuse reuse = null, Made made = null, Setup setup = null)
16811
+ // todo: add RegisterMany
16812
+ /// <summary>A single registration attribute</summary>
16813
+ public sealed class RegisterAttribute<TService, TImplementation, TReuse> : RegisterAttribute
16814
+ where TReuse : IReuse
16815
+ {
16816
+ /// <summary>In this case there are compile-time type constraints for the Implementation and Service types</summary>
16817
+ public override bool TypesAreStaticallyChecked => true;
16818
+
16819
+ /// <summary>Creates the registration attribute</summary>
16820
+ public RegisterAttribute()
16821
+ {
16822
+ ServiceType = typeof(TService);
16823
+ ImplementationType = typeof(TImplementation);
16824
+ ReuseType = typeof(TReuse);
16825
+ }
16703
16826
}
16704
16827
16705
16828
/// <summary>Ports some methods from .Net 4.0/4.5</summary>
0 commit comments