C
C#17mo ago
rcnespoli

❔ Builder with generics

Is possible create a builder that have classes with different parameters? An example
public class CommandHandlerFactory
{
private readonly ICommandHandler<CreateGoogleAccountCommand> _googleAccountCommandHandler;
private readonly ICommandHandler<CreateYahooAccountCommand> _yahooAccountCommandHandler;

public CommandHandlerFactory(ICommandHandler<CreateGoogleAccountCommand> googleAccountCommandHandler, ICommandHandler<CreateYahooAccountCommand> yahooAccountCommandHandler)
{
_googleAccountCommandHandler = googleAccountCommandHandler;
_yahooAccountCommandHandler = yahooAccountCommandHandler;
}

public ICommandHandler<T> Build<T>(ProviderAvaiablesEnum providers) where T : ICommand
{

var builder = new Dictionary<ProviderAvaiablesEnum, ICommandHandler<T>>
{
{ ProviderAvaiablesEnum.Google, _googleAccountCommandHandler },
{ ProviderAvaiablesEnum.Yahoo _yahooAccountCommandHandler },
};
return builder[providers];
}
}

// Command Handler interface
public interface ICommandHandler<in T> where T : ICommand
{
Task<CommandResult> Execute(T command, CancellationToken cancellationToken = default);
}

// Command interface
public interface ICommand
{
public ProviderAvaiablesEnum ProviderAvaiables { get; set; }
}

// Yahoo interface
public class CreateYahooAccountCommand : ICommand
{
public ProviderAvaiablesEnum ProviderAvaiables { get; set; } = ProviderAvaiablesEnum.Yahoo
....
}
public class CommandHandlerFactory
{
private readonly ICommandHandler<CreateGoogleAccountCommand> _googleAccountCommandHandler;
private readonly ICommandHandler<CreateYahooAccountCommand> _yahooAccountCommandHandler;

public CommandHandlerFactory(ICommandHandler<CreateGoogleAccountCommand> googleAccountCommandHandler, ICommandHandler<CreateYahooAccountCommand> yahooAccountCommandHandler)
{
_googleAccountCommandHandler = googleAccountCommandHandler;
_yahooAccountCommandHandler = yahooAccountCommandHandler;
}

public ICommandHandler<T> Build<T>(ProviderAvaiablesEnum providers) where T : ICommand
{

var builder = new Dictionary<ProviderAvaiablesEnum, ICommandHandler<T>>
{
{ ProviderAvaiablesEnum.Google, _googleAccountCommandHandler },
{ ProviderAvaiablesEnum.Yahoo _yahooAccountCommandHandler },
};
return builder[providers];
}
}

// Command Handler interface
public interface ICommandHandler<in T> where T : ICommand
{
Task<CommandResult> Execute(T command, CancellationToken cancellationToken = default);
}

// Command interface
public interface ICommand
{
public ProviderAvaiablesEnum ProviderAvaiables { get; set; }
}

// Yahoo interface
public class CreateYahooAccountCommand : ICommand
{
public ProviderAvaiablesEnum ProviderAvaiables { get; set; } = ProviderAvaiablesEnum.Yahoo
....
}
Compiler error, Argument type 'Account.Importer.Domain.Commands.Contracts.ICommandHandler<Account.Importer.Domain.Commands.Contracts.CreateGoogleAccountCommand>' is not assignable to parameter type 'Account.Importer.Domain.Commands.Contracts.ICommandHandler<T>'
7 Replies
phaseshift
phaseshift17mo ago
Generally, yes, but not with your Build<T> method, because T could be more derived than CreateGoogleAccountCommand, in which case its not valid
rcnespoli
rcnespoliOP17mo ago
So in this case how can I deal with this?
Omnissiah
Omnissiah17mo ago
essentially you can't, you either make a hack or you use object and casting but effectively i see the in T 🤔 ah no it's for Execute
rcnespoli
rcnespoliOP17mo ago
Yeah, I think it's not good use object or something casting
Omnissiah
Omnissiah17mo ago
i know the problem (of contravariance) is builder would be of the type of the interface with the less derived type Execute(ICommand command) but you are assigning it an interface with a more derived type Execute(CreateYahooAccountCommand command) so it can't cast because it would expose ICommand parameter which really would be for example a CreateYahooAccountCommand since it being ICommand you could really pass anything that inherits from that, not just CreateYahooAccountCommand
rcnespoli
rcnespoliOP17mo ago
Yeah.. i changed the approach.. I appreciate your time, thank you
Accord
Accord17mo ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
Want results from more Discord servers?
Add your server