简体   繁体   中英

How do I create an instance of a generic type with a parameter of type list

I have a generic class Result that looks like this

public class Result<T>
{
    public List<Error> Errors { get; set; } = new List<Error>();

    public T ResultObject { get; set; }

    public Result(List<Error> errors)
    {
        Errors = errors;
        Success = false;
    }
}

I try to create an instance like this:

public Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
{
    var context = new ValidationContext<TRequest>(request);

    var failures = _validators
        .Select(v => v.Validate(context))
        .SelectMany(result => result.Errors)
        .Where(f => f != null)
        .ToList();

    if (failures.Count != 0)
    {
        var responseType = typeof(TResponse);
        // This is the important line
        return Task.FromResult(Activator.CreateInstance(responseType, new object[] { failures.Select(x => new Error(x.ErrorMessage)).ToList() }) as TResponse);
    }

    return next();
}

TResponse is of type Result<GetUserFlow> . GetUserFlow is a dto but not important in this case. When I run my code I get the following error:

System.MissingMethodException: Constructor on type 'Heimdall.Application.Result`1[[Heimdall.Application.Dtos.GetUserFlow, Heimdall.Application, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' not found.

I guess the problem is that when passing a list as parameter it isn't seen as one parameter but as many. Each created Error is one parameter. I couldn't find anything about this topic.

You can invoke the correct constructor with:

constructorInfo.Invoke(new object[] { failures.Select(x => new Error(x.ErrorMessage)).ToList() }) as TResponse

To get the constructor, use somthing like this:

responseType.GetConstructors()[0]
// if you have multiple constructors, ensure the correct one with:
responseType.GetConstructor(new Type[]{ typeof(List<Error>) })

By the way, you may find the factory pattern much easier.

Pass through to the Handle function a factory delegate Func<List<Errors>, TResponse> and use that delegate to call the constructor.

public Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken,
  RequestHandlerDelegate<TResponse> next, Func<List<Errors>, TResponse> responseCreator)
{
....
    return Task.FromResult(responseCreator(
        failures.Select(x => new Error(x.ErrorMessage)).ToList()
    ));
....
}

You call it like this:

 var result = Handle(...., errors => new Result<GetUserFlow>(errors));

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