Как вызвать функцию generi c из списка объектов - PullRequest
1 голос
/ 27 марта 2020

У меня есть общий список c объектов, но все типы в списке разные. Однако при выполнении итерации по списку объектов и последующем вызове функции generi c тип T, определенный в generi c, имеет тип Object. Как я могу заставить сопоставление с образцом работать так, чтобы тип T соответствовал конкретному типу проверяемого объекта? Например, в нижеприведенном надуманном примере при вызове Validate для ValidationService строка

  if(validator is IValidator<T> typedValidator)

всегда завершается ошибкой, поскольку тип T является объектом, а физическая реализация будет IValidator<Widget> или IValidator<Entity>. Как мне изменить метод DemonstrateProblem(), чтобы при вызове validationService.Validate использовался конкретный тип функции, а не тип типа, определенный в List<object>? Чтобы сделать его немного сложнее, мой реальный код также асинхронный, поэтому мне нужно возвращаемое значение Task<IValidationResult<T>>

namespace Contrived
{
    public interface IValidator { }
    public interface IValidationResult<T> { }
    public interface IValidator<T> : IValidator
    {
        IValidationResult<T> Validate(T entity);
    }

    public class ValidationResult<T> : IValidationResult<T>
    {
       public bool IsValid { get; set; }
    }

    public class Entity
    {
        public int Id { get; set; }
        public string SomeProperty { get; set; }
    }

    public class EntityValidator : Contrived.IValidator<Entity>
    {
        public IValidationResult<Entity> Validate(Entity entity)
        {
            return new ValidationResult<Entity>() { IsValid = true };
        }
    }

    public class Widget
    {
        public Guid UniqueIdentifier { get; set; }
    }

    public class WidgetValidator : IValidator<Widget>
    {
        public IValidationResult<Widget> Validate(Widget entity)
        {
            return new ValidationResult<Widget>() { IsValid = true };
        }
    }

    public class ValidationService
    {
        private readonly Dictionary<Type, IValidator> validators;

        public ValidationService(Dictionary<Type, IValidator> validators)
        {
            this.validators = validators;
        }
        public IValidationResult<T> Validate<T>(T validatingObject)
        {
            var validator = validators[validatingObject.GetType()];
            if (validator is IValidator<T> typedValidator)
            {
                return typedValidator.Validate(validatingObject);
            }
            else throw new UnknownValidationType($"No known validator for type of {validatingObject.GetType()}");
        }
    }

    public class ServiceUser
    {
        private readonly ValidationService validationService;

        public ServiceUser(ValidationService validationService)
        {
            this.validationService = validationService;
        }

        public void DemonstrateProblem()
        {
            Widget widget = new Widget() { UniqueIdentifier = Guid.NewGuid() };
            Entity entity = new Entity() { Id = 1, SomeProperty = "You know" };

            List<object> ObjectsToBeValidated = new List<object>() { widget, entity };
            foreach(var t in ObjectsToBeValidated)
            {
                validationService.Validate(t);//The Generic type of T is Object because that is the type of the List.  
                //How to get to be the concrete type of Widget and Entity?
            }
        }
    }

    public class UnknownValidationType : Exception {
        public UnknownValidationType(string message) : base(message)
        {

        }
    }
}
...