Skip to content

Commit 8892117

Browse files
author
maximv
committed
fixed: #315
1 parent bcff8da commit 8892117

File tree

2 files changed

+35
-24
lines changed

2 files changed

+35
-24
lines changed

src/DryIoc/Container.cs

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2917,18 +2917,17 @@ public static bool TryInterpret(IResolverContext r, Expression expr,
29172917
if (!TryInterpretMethodCall(r, m, paramExprs, paramValues, parentArgs, useFec, ref instance))
29182918
return false;
29192919
}
2920-
else if (operandExpr is InvocationExpression i &&
2921-
i.Expression is ConstantExpression cd &&
2922-
cd.Value is FactoryDelegate d)
2920+
else if (operandExpr is InvocationExpression invokeExpr &&
2921+
invokeExpr.Expression is ConstantExpression cd && cd.Value is FactoryDelegate facDel)
29232922
{
29242923
// The majority of cases the delegate will be a well known `FactoryDelegate` - so calling it directly
2925-
if (i.Arguments[0] == FactoryDelegateCompiler.ResolverContextParamExpr)
2926-
result = d(r);
2927-
else if (i.Arguments[0] == ResolverContext.RootOrSelfExpr)
2928-
result = d(r.Root ?? r);
2929-
else if (TryInterpret(r, i.Arguments[0], paramExprs, paramValues, parentArgs, useFec,
2930-
out var resolver))
2931-
result = d((IResolverContext) resolver);
2924+
var rArg = invokeExpr.Arguments[0]; // todo: @perf optimize for a OneArgumentInvocationExpression
2925+
if (rArg == FactoryDelegateCompiler.ResolverContextParamExpr)
2926+
result = facDel(r);
2927+
else if (rArg == ResolverContext.RootOrSelfExpr)
2928+
result = facDel(r.Root ?? r);
2929+
else if (TryInterpret(r, rArg, paramExprs, paramValues, parentArgs, useFec, out var resolver))
2930+
result = facDel((IResolverContext)resolver);
29322931
else return false;
29332932
return true;
29342933
}
@@ -3006,6 +3005,18 @@ i.Expression is ConstantExpression cd &&
30063005
{
30073006
var invokeExpr = (InvocationExpression)expr;
30083007
var delegateExpr = invokeExpr.Expression;
3008+
if (delegateExpr is ConstantExpression dc && dc.Value is FactoryDelegate facDel)
3009+
{
3010+
var rArg = invokeExpr.Arguments[0]; // todo: @perf optimize for a OneArgumentInvocationExpression
3011+
if (rArg == FactoryDelegateCompiler.ResolverContextParamExpr)
3012+
result = facDel(r);
3013+
else if (rArg == ResolverContext.RootOrSelfExpr)
3014+
result = facDel(r.Root ?? r);
3015+
else if (TryInterpret(r, rArg, paramExprs, paramValues, parentArgs, useFec, out var resolver))
3016+
result = facDel((IResolverContext)resolver);
3017+
else return false;
3018+
return true;
3019+
}
30093020

30103021
// The Invocation of Func is used for splitting the big object graphs
30113022
// so we can ignore this split and go directly to the body
@@ -3015,23 +3026,20 @@ i.Expression is ConstantExpression cd &&
30153026
#if !SUPPORTS_DELEGATE_METHOD
30163027
return false;
30173028
#else
3018-
if (!TryInterpret(r, delegateExpr, paramExprs, paramValues, parentArgs, useFec, out var delegateObj)) // todo: @perf avoid calling the TryInterpret for the known constant of FactoryDelegate
3029+
if (!TryInterpret(r, delegateExpr, paramExprs, paramValues, parentArgs, useFec, out var delegateObj))
30193030
return false;
30203031

30213032
var lambda = (Delegate)delegateObj;
30223033
var argExprs = invokeExpr.Arguments.ToListOrSelf(); // todo: @perf recognize the OneArgumentInvocationExpression
30233034
if (argExprs.Count == 0)
30243035
result = lambda.GetMethodInfo().Invoke(lambda.Target, ArrayTools.Empty<object>());
3025-
else
3036+
else // it does not make sense to avoid array allocating for the single argument because we still need to pass array to the Invoke call
30263037
{
3027-
var args = new object[argExprs.Count]; // todo: @perf avoid allocating for the single argument
3038+
var args = new object[argExprs.Count];
30283039
for (var i = 0; i < args.Length; i++)
3029-
if (!TryInterpret(r, argExprs[i], paramExprs, paramValues, parentArgs, useFec, out args[i])) // todo: @perf simplify for the single argument `r` of ResolverContext for FactoryDelegate
3040+
if (!TryInterpret(r, argExprs[i], paramExprs, paramValues, parentArgs, useFec, out args[i]))
30303041
return false;
3031-
if (lambda is FactoryDelegate fd)
3032-
result = fd.Invoke((IResolverContext)args[0]);
3033-
else
3034-
result = lambda.GetMethodInfo().Invoke(lambda.Target, args);
3042+
result = lambda.GetMethodInfo().Invoke(lambda.Target, args);
30353043
}
30363044
return true;
30373045
#endif
@@ -3364,7 +3372,7 @@ private static bool TryInterpretMethodCall(IResolverContext r, Expression expr,
33643372
r = r.Root ?? r;
33653373
if (!TryInterpret(r, callArgs[0], paramExprs, paramValues, parentArgs, useFec, out var service))
33663374
return false;
3367-
result = r.SingletonScope.TrackDisposable(service, (int) ConstValue(callArgs[1]));
3375+
result = r.SingletonScope.TrackDisposable(service, (int)ConstValue(callArgs[1]));
33683376
return true;
33693377
}
33703378
}
@@ -4726,9 +4734,10 @@ internal static bool TryGetUsedInstance(this IResolverContext r, Type serviceTyp
47264734
|| r.SingletonScope.TryGetUsedInstance(r, serviceType, out instance);
47274735
}
47284736

4729-
/// A bit if sugar to track disposable in singleton or current scope
4737+
// todo: @perf no need to check for IDisposable in TrackDisposable
4738+
/// <summary>A bit if sugar to track disposable in the current scope or in the singleton scope as a fallback</summary>
47304739
public static T TrackDisposable<T>(this IResolverContext r, T instance) where T : IDisposable =>
4731-
(T)(r.SingletonScope ?? r.CurrentScope).TrackDisposable(instance);
4740+
(T)(r.SingletonScope ?? r.CurrentScope).TrackDisposable(instance); // todo: @fix check the scope first
47324741
}
47334742

47344743
/// <summary>The result delegate generated by DryIoc for service creation.</summary>
@@ -11669,7 +11678,8 @@ public bool TryGet(out object item, int id)
1166911678
return false;
1167011679
}
1167111680

11672-
// todo: consider adding the overload without `disposalOrder`
11681+
// todo: @perf consider adding the overload without `disposalOrder`
11682+
// todo: @perf we always know that item is IDisposable because it is being checked upper in stack, so we may remove the check here
1167311683
/// <summary>Can be used to manually add service for disposal</summary>
1167411684
public object TrackDisposable(object item, int disposalOrder = 0)
1167511685
{
@@ -12089,7 +12099,8 @@ public static object GetScopedOrSingletonViaFactoryDelegate(IResolverContext r,
1208912099
internal static readonly MethodInfo GetScopedOrSingletonViaFactoryDelegateMethod =
1209012100
typeof(CurrentScopeReuse).GetTypeInfo().GetDeclaredMethod(nameof(GetScopedOrSingletonViaFactoryDelegate));
1209112101

12092-
/// Subject
12102+
/// <summary>Tracks the Unordered disposal in the current scope or in the singleton as fallback</summary>
12103+
[MethodImpl((MethodImplOptions)256)]
1209312104
public static object TrackScopedOrSingleton(IResolverContext r, object item) =>
1209412105
(r.CurrentScope ?? r.SingletonScope).TrackDisposable(item);
1209512106

test/DryIoc.IssuesTests/GHIssue315_Combining_RegisterDelegate_with_TrackingDisposableTransients_rule_throws_TargetParameterCountException.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace DryIoc.IssuesTests
77
public class GHIssue315_Combining_RegisterDelegate_with_TrackingDisposableTransients_rule_throws_TargetParameterCountException
88
{
99
[Test]
10-
public void Test()
10+
public void Test_RegisterDelegate()
1111
{
1212
var container = new Container(rules => rules.WithTrackingDisposableTransients());
1313
container.RegisterDelegate<Foo>(c => new Bar());

0 commit comments

Comments
 (0)