halcwb
halcwb

Reputation: 1480

Structuremap constructor overloading

I have a command class that needs to have 2 constructors. However, using structuremap it seems that I can only specify one constructor to be used. I have solved the problem for now by subtyping the specific command class, which each implementation implementing it's own interface and constructor. Like the code below shows. The ISelectCommand implements two separate interfaces for the string constructor and the int constructor, just for the sake of registering the two subtypes using structuremap.

However, I consider this a hack and I just wonder why is it not possible for structuremap to resolve the constructor signature by the type passed in as parameter for the constructor? Then I could register the SelectProductCommand as an ISelectCommand and instantiate it like: ObjectFactury.With(10).Use>(); orObjectFactury.With("testproduct").Use>();

public class SelectProductCommand : ISelectCommand<IProduct>,
ICommand, IExecutable
{
   private readonly Func<Product, Boolean> _selector;
   private IEnumerable<IProduct> _resultList;

   public SelectProductCommand(Func<Product, Boolean> selector)
   {
       _selector = selector;
   }

   public IEnumerable<IProduct> Result
   {
       get { return _resultList; }
   }

   public void Execute(GenFormDataContext context)
   {
       _resultList = GetProductRepository().Fetch(context,
_selector);
   }

   private Repository<IProduct, Product> GetProductRepository()
   {
       return ObjectFactory.GetInstance<Repository<IProduct,
Product>>();
   }
}

public class SelectProductIntCommand: SelectProductCommand
{
    public SelectProductIntCommand(Int32 id): base(x =>
 x.ProductId == id) {}
}

public class SelectProductStringCommand: SelectProductCommand
{
    public SelectProductStringCommand(String name): base(x =>
x.ProductName.Contains(name)) {}
}

P.s. I know how to tell structuremap what constructor map to use, but my again my question is if there is a way to have structuremap select the right constructor based on the parameter passed to the constructor (i.e. using regular method overloading).

Upvotes: 0

Views: 834

Answers (2)

halcwb
halcwb

Reputation: 1480

I think I solved the problem using a small utility class. This class gets the concrete type from ObjectFactory and uses this type to construct the instance according to the parameters past into the factory method. Now on the 'client' side I use ObjectFactory to create an instance of CommandFactory. The implementation of CommandFactory is in another solution and thus the 'client solution' remains independent of the 'server' solution.

public class CommandFactory
{

    public ICommand Create<T>()
    {
        return Create<T>(new object[] {});
    }

    public ICommand Create<T>(object arg1)
    {
        return Create<T>(new[] {arg1});
    }

    public ICommand Create<T>(object arg1, object arg2)
    {
        return Create<T>(new[] {arg1, arg2});
    }

    public ICommand Create<T>(object arg1, object arg2, object arg3)
    {
        return Create<T>(new[] {arg1, arg2, arg3});
    }

    public ICommand Create<T>(object[] arguments)
    {
        return (ICommand)Activator.CreateInstance(GetRegisteredType<T>(), arguments);
    }

    public static Type GetRegisteredType<T>()
    {
        return ObjectFactory.Model.DefaultTypeFor(typeof (T));
    }
}

Upvotes: 1

Henning
Henning

Reputation: 685

The short answer is this post by the creator of Structuremap.

The long answer is regarding the structure you have in that piece of code. In my view, a command is by definition a "class" that does something to an "entity", i.e it modifies the class somehow. Think CreateNewProductCommand.

Here you are using commands for querying, if I'm not mistaken. You also have a bit of a separation of concern issue floating around here. The command posted defines what to do and how to do it, which is to much and you get that kind of Service location you're using in

private Repository<IProduct, Product> GetProductRepository()
{
    return ObjectFactory.GetInstance<Repository<IProduct, Product>>();
}

The way I'd structure commands is to use CreateProductCommand as a data contract, i.e it only contains data such as product information. Then you have a CreateProductCommandHandler which implements IHandles<CreateProductCommand> with a single method Handle or Execute. That way you get better separation of concern and testability.

As for the querying part, just use your repositores directly in your controller/presenter, alternatively use the Query Object pattern

Upvotes: 1

Related Questions