Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Q&A

Welcome to Software Development on Codidact!

Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.

Post History

50%
+0 −0
Q&A Working with a generic class that uses a type that should be of generic type

I have followed Nick Chapsas' tutorial to avoid throwing a ValidationException to treat validation errors and instead rely on LanguageExt.Common.Result<> from LanguageExt library. I have ma...

0 answers  ·  posted 1y ago by Alexei‭

Question c# generics .net .net-6
#1: Initial revision by user avatar Alexei‭ · 2022-07-13T08:12:21Z (over 1 year ago)
Working with a generic class that uses a type that should be of generic type
I have followed [Nick Chapsas' tutorial ](https://www.youtube.com/watch?v=a1ye9eGTB98) to avoid throwing a ValidationException to treat validation errors and instead rely on `LanguageExt.Common.Result<>` from [LanguageExt library](https://github.com/louthy/language-ext).

I have managed to develop a working solution that relies on MediatR (which uses queries, commands and validators for those), but I feel I am violating the DRY principle. 

The relevant code is below:

### A sample command

```c#
public class CreateDummyModelCommand : IRequest<Result<int>>
{
	public string? Code { get; set; }
	public string? Name { get; set; }
}

/// <summary>
/// this relies on Nick Chapsas idea of not using ValidationExceptions, but return Values:
/// https://www.youtube.com/watch?v=a1ye9eGTB98
/// </summary>
internal class CreateDummyModelCommandHandler : IRequestHandler<CreateDummyModelCommand, Result<int>>
{
	private readonly IValidationUtils<CreateDummyModelCommand, int> _validationUtils;

	public CreateDummyModelCommandHandler(IValidationUtils<CreateDummyModelCommand, int> validationUtils)
	{
		_validationUtils = validationUtils;
	}

	public async Task<Result<int>> Handle(CreateDummyModelCommand request, CancellationToken token)
	{
		var validationResult = await _validationUtils.IsValid(request, token);
		if (validationResult.IsFaulted)
			return validationResult;

		var r = new Random();
		return await Task.FromResult(r.Next(1000));
	}
}
```

`Result<A>` provides an implicit cast operator that allow to return a `Result<A>` and the function to return an `A`.

I will add `ValidationUtils` class for completeness, but I think it is less relevant in this case:

```c#
internal class ValidationUtils<TReq, TRes> : IValidationUtils<TReq, TRes> 
	where TReq : class, IBaseRequest
{
	private readonly IValidator<TReq> _validator;

	public ValidationUtils(IValidator<TReq> validator)
	{
		_validator = validator;
	}

	public async Task<Result<TRes>> IsValid(TReq request, CancellationToken token = default)
	{
		var validationResult = await _validator.ValidateAsync(request, token);
		if (!validationResult.IsValid)
		{
			var validationException = new ValidationException(validationResult.Errors);
			return new Result<TRes>(validationException);
		}

		var dummyObj = Activator.CreateInstance<TRes>();
		return dummyObj;
	}
}
```

What I do not like is that virtually any command must include that validation logic at the beginning and I feel that it can be put in a MediatR pipeline behaviour that would execute for each command and trigger the validation, if one is defined. My non-working code is currently the following:

```c#
internal class ValidationBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
	where TRequest : class, IRequest<TResponse>, IBaseRequest
	where TResponse: struct
{
	private readonly IValidationUtils<TRequest, TResponse> _validationUtils;

	///
	public ValidationBehaviour(IValidationUtils<TRequest, TResponse> validationUtils)
	{
		_validationUtils = validationUtils;
	}

	public async Task<TResponse> Handle(TRequest request, CancellationToken token,
		RequestHandlerDelegate<TResponse> next)
	{
		bool isResult = typeof(TResponse).GetGenericTypeDefinition() == typeof(Result<>);
		if (!isResult)
			return await next();

		var validationResult = await _validationUtils.IsValid(request, token);
		if (validationResult.IsFaulted)
			return validationResult as dynamic;

		return await next();
	}
}
```

This compiles, but it does not work because since `TResponse` is actually a `Result<>`, `validationResult` is a `Result<Result<>>`.

One way would have been to work with another generic type to indicate the underlying type of the Result<>, but I cannot change the behavior's signature. While using Result<> usage is convenient, I could break this dependency and use my own class, but I feel I am reinventing the wheel here.

Any idea about how to make this work?