Skip to content

Commit

Permalink
making ConnectImplementationsToTypesClosing smart enough to deal with…
Browse files Browse the repository at this point in the history
… co/contra variance better. Closes GH-320
  • Loading branch information
jeremydmiller committed Jan 27, 2015
1 parent b6b3f15 commit 3b167d8
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 0 deletions.
@@ -0,0 +1,45 @@
using System.Diagnostics;
using System.Linq;
using NUnit.Framework;
using StructureMap.Graph;

namespace StructureMap.Testing.Bugs
{
[TestFixture]
public class Bug_320_generic_parent_child_relationship
{
public class Parent { };
public class Child : Parent { }
public class ConcreteChild : Child { }

public interface IGeneric<in T> where T : class { }
public class GenericClass1 : IGeneric<Parent> { }
public class GenericClass2 : IGeneric<Child> { }
//public class GenericClass3 : IGeneric<ConcreteChild> { }

[Test]
public void StructureMap_Resolves_Generic_Child_Classes()
{
typeof(IGeneric<ConcreteChild>).IsAssignableFrom(typeof(GenericClass1)).ShouldBeTrue();
typeof(IGeneric<ConcreteChild>).IsAssignableFrom(typeof(GenericClass2)).ShouldBeTrue();
//Assert.IsTrue(typeof(IGeneric<ConcreteChild>).IsAssignableFrom(typeof(GenericClass3)));

var container = new Container(cfg =>
{
cfg.Scan(scan =>
{
scan.TheCallingAssembly();
scan.ConnectImplementationsToTypesClosing(typeof(IGeneric<>));
});
});

var what = container.WhatDoIHave();
Debug.WriteLine(what);

var instances = container.GetAllInstances<IGeneric<ConcreteChild>>();

instances.Any(t => t.GetType() == typeof (GenericClass1)).ShouldBeTrue();
instances.Any(t => t.GetType() == typeof(GenericClass2)).ShouldBeTrue();
}
}
}
1 change: 1 addition & 0 deletions src/StructureMap.Testing/StructureMap.Testing.csproj
Expand Up @@ -208,6 +208,7 @@
<Compile Include="Bugs\Bug_300_naive_can_be_plugged_into_tests.cs" />
<Compile Include="Bugs\Bug_313.cs" />
<Compile Include="Bugs\Bug_318.cs" />
<Compile Include="Bugs\Bug_320_generic_parent_child_relationship.cs" />
<Compile Include="Bugs\Bug_321_Singleton_exception_messages.cs" />
<Compile Include="Bugs\Bug_322_class_with_multiple_constructors.cs" />
<Compile Include="Bugs\BuildUpBug.cs" />
Expand Down
9 changes: 9 additions & 0 deletions src/StructureMap/Graph/CloseGenericFamilyPolicy.cs
Expand Up @@ -23,6 +23,15 @@ public PluginFamily Build(Type type)

if (!_graph.Families.Has(basicType))
{
// RIGHT HERE: do the connections thing HERE!
var connectingTypes = _graph.ConnectedConcretions.Where(x => x.CanBeCastTo(type)).ToArray();
if (connectingTypes.Any())
{
var family = new PluginFamily(type);
connectingTypes.Each(family.AddType);

return family;
}

return _graph.Families.ToArray().FirstOrDefault(x => type.GetTypeInfo().IsAssignableFrom(x.PluginType.GetTypeInfo()));
}
Expand Down
3 changes: 3 additions & 0 deletions src/StructureMap/Graph/GenericConnectionScanner.cs
Expand Up @@ -51,7 +51,10 @@ public void Apply(PluginGraph graph)
_concretions.Where(x => x.CanBeCastTo(@interface)).Each(type => expression.Add(type));
});

_concretions.Each(t => graph.ConnectedConcretions.Fill(t));
registry.As<IPluginGraphConfiguration>().Configure(graph);


}
}
}
8 changes: 8 additions & 0 deletions src/StructureMap/Graph/PluginGraph.cs
Expand Up @@ -27,6 +27,12 @@ public class PluginGraph : IPluginGraph, IDisposable
/// </summary>
public readonly Policies Policies = new Policies();

/// <summary>
/// Holds a cache of concrete types that can be considered for closing generic interface
/// types
/// </summary>
public readonly IList<Type> ConnectedConcretions = new List<Type>();

public PluginGraph()
{
_profiles =
Expand Down Expand Up @@ -303,4 +309,6 @@ void IDisposable.Dispose()
_families.ClearAll();
}
}


}

0 comments on commit 3b167d8

Please sign in to comment.