Reputation: 16276
I am following this document to use typed factory and pass parameters into constructor. The typed factory is giving me this error when I try to pass 2 parameters (1,"fo") as shown in the code.
public class SomeClass {
public ITypedFactory2 F2 { get; set; }
public void SomeFunction() {
var req = F2.Create<IGetFooRequest>(1, "fo"); // ERROR HERE
}
}
public class GetFooRequest : IGetFooRequest {
public int Bar { get; private set; }
public string Ton { get; private set; }
public GetFooRequest(int bar, string ton ) {
Bar = bar;
Ton = ton;
}
}
public interface IGetFooRequest{
int Bar { get; }
string Ton { get; }
}
public interface ITypedFactory2 {
T Create<T>(int param1, string param2);
void Release(object t);
}
and this is the windsor installer part...
container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<ITypedFactory2>().AsFactory());
container.Register(AllTypes
.FromAssemblyContaining<IGetFooRequest>()
.Where(type => type.Name.EndsWith("Request"))
.WithService.AllInterfaces().LifestyleTransient());
Why it says could not resolve non-optional dependency...? I have passed in (1,"fo"); I really don't understand why this is happening... Please help.
Upvotes: 3
Views: 4396
Reputation: 322
If you want to resolve by Type over parameter name you can create your own ComponentSelector
:
public class ComponentSelector : DefaultTypedFactoryComponentSelector
{
protected override Arguments GetArguments(MethodInfo method, object[] arguments)
{
if (arguments == null)
return null;
Arguments argumentMap = new Arguments();
ParameterInfo[] parameters = method.GetParameters();
List<Type> types = parameters.Select(p => p.ParameterType).ToList();
List<Type> duplicateTypes = types.Where(t => types.Count(type => type == t) > 1).ToList();
for (int i = 0; i < parameters.Length; i++)
{
if (duplicateTypes.Contains(parameters[i].ParameterType))
argumentMap.Add(parameters[i].Name, arguments[i]);
else
argumentMap.Add(parameters[i].ParameterType, arguments[i]);
}
return argumentMap;
}
}
As you can see in my implementation, you need to handle the case when your constructor has multiple parameters with the same type.
In that case you have to resolve by parameter name because Castle.Windsor
will use the first parameter of a type for every parameter that has the same type.
To use your own ComponentSelector
you have to register it with your IWindsorContainer
as well:
container.Register(Component.For<ComponentSelector, ITypedFactoryComponentSelector>());
Finally you have to tell your factory to use your own ComponentSelector
as its component selector:
container.Register(Component.For<ITypedFactory2>().AsFactory(f => f.SelectedWith<ComponentSelector>()));
For more information check the official documentation on how to use custom component selectors.
Upvotes: 1
Reputation: 96
I had the same question and just figured out the answer. The parameters' names of your factory method and those of your class constructor must match, case insensitive.
so change your factory interface to
public interface ITypedFactory2 {
T Create<T>(int **bar**, string **ton**);
void Release(object t);
}
or your class to
public class GetFooRequest : IGetFooRequest {
public int Bar { get; private set; }
public string Ton { get; private set; }
public GetFooRequest(int **param1**, string **param2**) {
Bar = bar;
Ton = ton;
}
}
Upvotes: 8
Reputation: 16276
I looked at my own code and say, (int param1, string param2) doesn't look good. Let me use (int bar, string ton) ... and that naming fixed the problem. LoL Unbelievable, and I don't see that document mentioned the significance of naming.
Luckily I do remember the intro here says dependencies are resolved first by name, then by type. So that is the by name part doing its work, and the by type part gone into water. Anyway, I am glad I figured out how to use it, so I share my answer here with whoever needs it.
Upvotes: 2