I'm using c# and I'm using CQRS So let's image this scenario
public async Task<Response<SaleProducts>> Handle(CreateSaleProductCommand request, CancellationToken cancellationToken)
{
var newEntity = MyCustomerMapper.Mapper.Map<SaleProducts>(request);
if (newEntity is null)
throw new ApplicationException("There is a problem in mapper");
var itemToReturn = await _repositoryCommand.AddProductToSaleAsync(newEntity);
if(itemToReturn != null)
{
itemToReturn.Product = await _productQueryRepository.GetByIdAsync(itemToReturn.ProductId);
return new Response<SaleProducts>(itemToReturn);
}
else
throw new ApplicationException("There is a problem when saving the product");
}
so this function return Response<SaleProducts>
after saving.
Now I like to make some verification in my _repositoryCommand.AddProductToSaleAsync
.
So if verification is ok I return SaleProducts if not I return other value(like bool or string) for exepmle.
So is there any way to have something similar to this
public async Task<Response<SaleProducts | bool>> Handle(CreateSaleProductCommand request, CancellationToken cancellationToken)
return type SaleProducts | bool | string
CodePudding user response:
There is no build-in way to represent that in C# (unless count value tuples as one, but personally I prefer to use it when all elements can be present in the result). You can look into using Either
monad from some existing libraries like language-ext:
public async Task<Response<Either<string, SaleProducts>>> Handle()
Or OneOf
:
This library provides F# style
discriminatedunions for C#, using a custom type OneOf<T0, ... Tn>. An instance of this type holds a single value, which is one of the types in its generic argument list.
Which referes the similar problem as one of the common to solve with OneOf
:
The most frequent use case is as a return value, when you need to return different results from a method.
public OneOf<User, InvalidName, NameTaken> CreateUser(string username)
{
if (!IsValid(username)) return new InvalidName();
var user = _repo.FindByUsername(username);
if(user != null) return new NameTaken();
var user = new User(username);
_repo.Save(user);
return user;
}
And provides handy methods to work with it.
Or FluentResults
:
FluentResults is a lightweight .NET library developed to solve a common problem. It returns an object indicating success or failure of an operation instead of throwing/using exceptions.
CodePudding user response:
I would probably just use a tuple for this:
public async Task<Response<(SaleProducts? Products, string? Status)>> Handle(CreateSaleProductCommand request, CancellationToken cancellationToken)
Then your Handle
turns into:
public async Task<Response<SaleProducts>> Handle(CreateSaleProductCommand request, CancellationToken cancellationToken)
{
var newEntity = MyCustomerMapper.Mapper.Map<SaleProducts>(request);
if (newEntity is null)
throw new ApplicationException("There is a problem in mapper");
var (itemToReturn, textStatus) = await _repositoryCommand.AddProductToSaleAsync(newEntity);
if(itemToReturn != null)
{
itemToReturn.Product = await _productQueryRepository.GetByIdAsync(itemToReturn.ProductId);
return new Response<SaleProducts>(itemToReturn);
}
else
{
// Do whatever processing you want to do with textStatus
...
throw new ApplicationException("There is a problem when saving the product");
}
}