z4kn4fein / stashbox

A lightweight, fast, and portable dependency injection framework for .NET-based solutions.
https://z4kn4fein.github.io/stashbox
MIT License
140 stars 10 forks source link

When a type has been registered using .WithFactory(), properties of the concrete instance are injected against the interface, not the type #64

Closed Tobriand closed 5 years ago

Tobriand commented 5 years ago

First, new to DI and StashBox, so thanks (generally) and hope this is actually an issue, and not me misunderstanding how this is supposed to work.

When a type has been registered into a container using c.Register<IFoo>(typeof(Foo), x => x.WithFactory(s => new Foo())); and resolve is called against Foo, if Foo has any properties that are identified for injection, the attempt is instead made to inject them against IFoo rather than against Foo.

In particular, the below works (in the C# interactive pane in VS):

interface IFoo { }
interface IBar { string Name { get; set; } }
class Foo : IFoo { public IBar Bar { get; set; } }
class Bar : IBar { public string Name { get; set; } }
var c = new StashboxContainer(c => c.WithUnknownTypeResolution().WithMemberInjectionWithoutAnnotation());
c.Register<IFoo>(typeof(Foo));
c.Register<IBar>(typeof(Bar));
IFoo f = c.Resolve<IFoo>();
f

Whereas this version doesn't:

interface IFoo { }
interface IBar { string Name { get; set; } }
class Foo : IFoo { public IBar Bar { get; set; } }
class Bar : IBar { public string Name { get; set; } }
var c = new StashboxContainer(c => c.WithUnknownTypeResolution().WithMemberInjectionWithoutAnnotation());
c.Register<IFoo>(typeof(Foo), ctx => ctx.WithFactory(x => new Foo()));
c.Register<IBar>(typeof(Bar), ctx => ctx.WithFactory(x => new Bar()));
IFoo f = c.Resolve<IFoo>();
f

Instead it throws the following:

System.ArgumentException: Property 'IBar Bar' is not defined for type 'Submission#2+IFoo'
  + System.Linq.Expressions.Expression.Property(System.Linq.Expressions.Expression, System.Reflection.PropertyInfo)
  + Stashbox.BuildUp.Expressions.ExpressionBuilder.FillMembersExpression(Stashbox.IContainerContext, Stashbox.Entity.MemberInformation[], Stashbox.Registration.RegistrationContext, Stashbox.Resolution.ResolutionContext, System.Linq.Expressions.Expression)
  + Stashbox.BuildUp.Expressions.ExpressionBuilder.CreateFillExpression(Stashbox.IContainerContext, Stashbox.Registration.IServiceRegistration, System.Linq.Expressions.Expression, Stashbox.Resolution.ResolutionContext, System.Type)
  + Stashbox.BuildUp.ObjectBuilders.FactoryObjectBuilder.GetExpressionInternal(Stashbox.IContainerContext, Stashbox.Registration.IServiceRegistration, Stashbox.Resolution.ResolutionContext, System.Type)
  + Stashbox.BuildUp.ObjectBuilderBase.BuildDisposalTrackingAndFinalizerExpression(Stashbox.IContainerContext, Stashbox.Registration.IServiceRegistration, Stashbox.Resolution.ResolutionContext, System.Type)
  + Stashbox.BuildUp.ObjectBuilderBase.GetExpression(Stashbox.IContainerContext, Stashbox.Registration.IServiceRegistration, Stashbox.Resolution.ResolutionContext, System.Type)
  + Stashbox.Registration.ServiceRegistration.ConstructExpression(Stashbox.IContainerContext, Stashbox.Resolution.ResolutionContext, System.Type)
  + Stashbox.Registration.ServiceRegistration.GetExpression(Stashbox.IContainerContext, Stashbox.Resolution.ResolutionContext, System.Type)
  + Stashbox.ResolutionScope.Activate(Stashbox.Resolution.ResolutionContext, System.Type, object)
  + Stashbox.ResolutionScope.Resolve(System.Type, bool, object[])
  + Stashbox.DependencyResolverExtensions.Resolve<TKey>(Stashbox.IDependencyResolver, bool, object[])

This is the same exception thrown if you attempt the following, so it's probably what's happening:

interface IFoo { }
interface IBar { string Name { get; set; } }
class Foo : IFoo { public IBar Bar { get; set; } }
class Bar : IBar { public string Name { get; set; } }
var propertyFromFoo = typeof(Foo).GetProperty("Bar");
var tIFoo = typeof(IFoo);
var pIFoo = Expression.Parameter(tIFoo);
var expressionCallThatResultsInAnException = Expression.Property(pIFoo, propertyFromFoo.GetMethod);
z4kn4fein commented 5 years ago

Hey,

Thanks for reporting this issue, I see where the problem is, I'll fix it soon and put into the next version!

z4kn4fein commented 5 years ago

Published a new version with the fix to my pre-release nuget feed, could you please check that it works as expected? Thanks!

Tobriand commented 5 years ago

That was fast! Thanks for the fix - looks like it's behaving on the PreRelease version :)

z4kn4fein commented 5 years ago

released v2.8.4