Skip to content

Commit 5ba83d8

Browse files
committed
fixed: #390; fixed excessive memory in ImTools.Match for 2 item arrays
1 parent 22c572a commit 5ba83d8

File tree

3 files changed

+63
-13
lines changed

3 files changed

+63
-13
lines changed

src/DryIoc/Container.cs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,7 +1079,7 @@ internal static void TryThrowUnableToResolve(Request request)
10791079
str = request.Container
10801080
.GetAllServiceFactories(request.ServiceType, bothClosedAndOpenGenerics: true)
10811081
.Aggregate(str, (s, x) => s
1082-
.Append(x.Value.Reuse?.CanApply(request) ?? true ? " " : " without matching scope ")
1082+
.Append((x.Value.Reuse?.CanApply(request) ?? true) ? " " : " without matching scope ")
10831083
.Print(x));
10841084

10851085
if (str.Length != 0)
@@ -1171,8 +1171,9 @@ Factory IContainer.GetServiceFactoryOrDefault(Request request)
11711171
var factories = entry == null ? null
11721172
: entry is Factory factory ? new KV<object, Factory>(DefaultKey.Value, factory).One()
11731173
: entry.To<FactoriesEntry>().Factories
1174-
.Visit(new List<KV<object, Factory>>(2), (x, list) => list.Add(KV.Of(x.Key, x.Value))).ToArray(); // todo: optimize - we may not need ToArray here
1175-
1174+
.Visit(new List<KV<object, Factory>>(2), (x, list) => list.Add(KV.Of(x.Key, x.Value))).ToArray() // todo: optimize - we may not need ToArray here
1175+
.Match(x => x.Value != null); // filter out the Unregistered factories (see #390)
1176+
11761177
if (!factories.IsNullOrEmpty()) // check for the additional (not the fallback) factories, because we have the standard factories
11771178
{
11781179
if (Rules.HasDynamicRegistrationProvider(
@@ -1456,9 +1457,10 @@ IEnumerable<KV<object, Factory>> IContainer.GetAllServiceFactories(Type serviceT
14561457
private static IEnumerable<KV<object, Factory>> GetRegistryEntryKeyFactoryPairs(object entry) =>
14571458
entry == null
14581459
? Empty<KV<object, Factory>>()
1459-
: entry is Factory ? new[] { new KV<object, Factory>(DefaultKey.Value, (Factory)entry) }
1460+
: entry is Factory f ? new[] { new KV<object, Factory>(DefaultKey.Value, f) }
14601461
// todo: optimize
1461-
: entry.To<FactoriesEntry>().Factories.Visit(new List<KV<object, Factory>>(), (x, l) => l.Add(KV.Of(x.Key, x.Value))).ToArray();
1462+
: entry.To<FactoriesEntry>().Factories.Visit(new List<KV<object, Factory>>(), (x, l) => l.Add(KV.Of(x.Key, x.Value))).ToArray()
1463+
.Match(x => x.Value != null); // filter out the Unregistered factories
14621464

14631465
Expression IContainer.GetDecoratorExpressionOrDefault(Request request)
14641466
{
@@ -2709,19 +2711,23 @@ private Registry UnregisterServiceFactory(Type serviceType, object serviceKey =
27092711

27102712
var registry = WithServices(services);
27112713

2712-
var removedFactory = removed as Factory;
2713-
if (removedFactory != null)
2714-
registry.DropFactoryCache(removedFactory, hash, serviceType, serviceKey);
2714+
if (removed is Factory f)
2715+
registry.DropFactoryCache(f, hash, serviceType, serviceKey);
2716+
else if (removed is Factory[] fs)
2717+
foreach (var rf in fs)
2718+
registry.DropFactoryCache(rf, hash, serviceType, serviceKey);
27152719
else
2716-
(removed as Factory[] ??
2717-
((FactoriesEntry)removed).Factories.Enumerate().Select(f => f.Value).ToArray())
2718-
.ForEach(x => registry.DropFactoryCache(x, hash, serviceType, serviceKey));
2720+
foreach (var e in ((FactoriesEntry)removed).Factories.Enumerate())
2721+
registry.DropFactoryCache(e.Value, hash, serviceType, serviceKey);
27192722

27202723
return registry;
27212724
}
27222725

27232726
internal void DropFactoryCache(Factory factory, int hash, Type serviceType, object serviceKey = null)
27242727
{
2728+
if (factory == null)
2729+
return; // filter out Unregistered factory (see #390)
2730+
27252731
if (DefaultFactoryCache != null || KeyedFactoryCache != null)
27262732
{
27272733
if (factory.FactoryGenerator == null)

src/DryIoc/ImTools.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1874,7 +1874,7 @@ public static T[] Match<T>(this T[] source, Func<T, bool> condition)
18741874
{
18751875
var condition0 = condition(source[0]);
18761876
var condition1 = condition(source[1]);
1877-
return condition0 && condition1 ? new[] { source[0], source[1] }
1877+
return condition0 && condition1 ? source
18781878
: condition0 ? new[] { source[0] }
18791879
: condition1 ? new[] { source[1] }
18801880
: Empty<T>();
@@ -1913,7 +1913,7 @@ public static T[] Match<T, S>(this T[] source, S state, Func<S, T, bool> conditi
19131913
{
19141914
var condition0 = condition(state, source[0]);
19151915
var condition1 = condition(state, source[1]);
1916-
return condition0 && condition1 ? new[] { source[0], source[1] }
1916+
return condition0 && condition1 ? source
19171917
: condition0 ? new[] { source[0] }
19181918
: condition1 ? new[] { source[1] }
19191919
: Empty<T>();
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using NUnit.Framework;
2+
using System.Linq;
3+
4+
namespace DryIoc.IssuesTests
5+
{
6+
[TestFixture]
7+
public class GHIssue390_NullReferenceException_on_Unregister : ITest
8+
{
9+
public int Run()
10+
{
11+
Test1();
12+
return 1;
13+
}
14+
15+
[Test]
16+
public void Test1()
17+
{
18+
var implementationType1 = typeof(A);
19+
var implementationType2 = typeof(B);
20+
var interfaceType = typeof(ITargetInterface);
21+
22+
var container = new Container();
23+
container.Register(interfaceType, implementationType1, serviceKey: "foo");
24+
container.Register(interfaceType, implementationType2, serviceKey: "bar");
25+
26+
container.Unregister(interfaceType, serviceKey: "foo");
27+
28+
Assert.Throws<ContainerException>(() =>
29+
container.Resolve(interfaceType, "foo"));
30+
31+
var x = container.Resolve(interfaceType, "foo", IfUnresolved.ReturnDefault);
32+
Assert.IsNull(x);
33+
34+
var a = container.ResolveMany(interfaceType, ResolveManyBehavior.AsFixedArray);
35+
Assert.IsInstanceOf<B>(a.Single());
36+
37+
container.ClearCache(interfaceType);
38+
}
39+
40+
interface ITargetInterface {}
41+
class A : ITargetInterface {}
42+
class B : ITargetInterface {}
43+
}
44+
}

0 commit comments

Comments
 (0)