简体   繁体   中英

Constructor cannot call itself

I use Castle Windsor for the DI mechanism, and I'm stuck here. I use the constructor injection type which works fine.

But, when I declare some other class's constructor, I need to invoke the default constructor, where the DI magic takes place.

So, I have the following code:

private readonly IUserService UserService = null;

public CustomAccessAttribute(IUserService userService)
{
    this.UserService = userService;
}

public CustomAccessAttribute(bool someParam) : this() //here I'd like to call the above constructor
{
    ....           
}

but I get the error

Constructor 'CustomAccessAttribute.CustomAccessAttribute(bool)' cannot call itself

I don't want to put the userService object by myself inside of the this() call, because the DI container should do this. So, how can I fix that error?

I think you're attacking this in the wrong way.

If you want the DI container to choose the right overload, you must provide all the arguments you want to receive. Accepting a bool only won't help, since you actually need the IUserService interface as well. It won't make itself appear out of nowhere. Your DI needs to know that it exists and it must be passed to appropriate constructor.

What you need is:

private readonly IUserService UserService = null;
public CustomAccessAttribute(IUserService userService)
{
    this.UserService = userService;
}

public CustomAccessAttribute(IUserService userService, bool someParam) : this(userService) 
{         
}

Although, you usually want to make the constructor chaining outwards, from the least parameters to the most. So perhaps you'd want to do:

private readonly IUserService UserService = null;
public CustomAccessAttribute(IUserService userService) : this(userService, false)
{
}

public CustomAccessAttribute(IUserService userService, bool someParam)
{  
    this.UserService = userService;
}

Edit:

If the bool you want to pass to your constructor isn't available at injection time, then constructor injection is probably not the way to go at all. Perhaps a more suitable way would be to set it as a property, which could be set once that bool is available, or a factory pattern which will create the class instance for you when everything is available.

You appear to be confused as to how IoC works. When you want to create an instance of a class there is no 'Magic' that happens to pass the parameters in, and if you new up an instance of your CustomAccessAttribute manually, Windsor will have nothing to do with it as it won't know you're creating an instance. Windsor (usually) follows the following steps:

  1. You register your implementation of IUserService with your container
  2. You call myContainer.Resolve<CustomAccessAttribute>() (or resolve something with CustomAccessAttribute as a dependency)
  3. Your container looks at CustomAccessAttribute and sees that the constructor takes an IUserService
  4. Your container builds an implementation of IUserService and passes it into the constructor, then returns the new CustomAccessAttribute to you (or whoever needed it injecting)

None of these steps require any 'Magic', but they all require you to be interacting with the container itself, not just newing up instances and relying on DI Magic.

If you create a default constructor without the IUserService being passed in, you'll find that the IUserService one will be resolved anyway if you're using Resolve(), as Windsor will always resolve the constructor with the most parameters that it has registered implementations for.

The real question is why an attribute needs an IUserService in the first place, when they should only be used for metadata, not behaviour. I don't even think Windsor will happily resolve attributes without a bunch of extra setup, which hints at what a bad idea it is.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM