C # Используйте Generics для вызова переопределенного метода - PullRequest
0 голосов
/ 28 октября 2019

Я думаю, что я немного запутался в этом моменте, но я не могу решить эту проблему.

У меня есть интерфейс ILinkHandler<T> и 4 других класса обработчиков (наследование отэтот интерфейс), которые проверяют различные структуры ссылок. Из этого интерфейса у меня есть функция Task<List<T>> Validate(), которая выполняет проверку ссылок и возвращает Задачу> результатов. В зависимости от T, я возвращаю другую модель на Validate() (у меня есть 4 разные модели).

Мое консольное приложение выполняет следующие действия. Он вызывает метод Task<List<T>> Validate(); для каждого типа ссылки и создает некоторые журналы после получения результатов (обратите внимание, что Validate() равно async). Каждый журнал немного отличается, так как модель отличается, поэтому я переопределил метод с именем WriteResults(ModelX results, string name) и из типа ModelX (см. Конец вопроса, я опубликовал 2 примера), я делаю некоторые вещи по-другому (не важно в этомсфера я думаю, но могу предоставить подробности при необходимости). Этот метод НЕ является асинхронным.

Я хотел использовать Generics и мой интерфейс для создания метода (ValidateModel<T>), который обрабатывает правильный вызов переопределенного метода WriteResults из типа модели и вызываетValidate() метод из интерфейса.

Приведенный ниже код показывает, что я сделал, что это сработало, но часть if напоминает то, что у меня есть в моей главной записи, и я хочу избежать.

public void ValidateModel<T>(ILinkHandler<T> handler, string name) where T : class
{
    Console.WriteLine($"Validating {name}");
    var results = handler.Validate();

    if (typeof(T) == typeof(InternalLinksModel))
    {
        WriteResults(results.Result as List<InternalLinksModel>, name);
    }
    else // continue with other models
}

Вот что у меня в основном:

private static void Main(string[] args) 
{
    Console.WriteLine("Validating External_Links");
    var resultsForExternalLinks = ExternalLinkHandler.Validate();
    WriteResults(resultsForExternalLinks.Result, "External_Links");

    Console.WriteLine("Validating Image_Links");
    var resultsForImageLinks = ImageLinkHandler.Validate();
    WriteResults(resultsForImageLinks.Result, "Image_Links");

// and so on
}

Я хочу еще что-то подобное, если это возможно, но это не компилируется:

public void ValidateModel<T>(ILinkHandler<T> handler, string name) where T : class
{
    Console.WriteLine($"Validating {name}");
    var results = handler.Validate();

    WriteResults<T>(results.Result as List<T>, name);
}

Вот определение WriteResults (обратите внимание, что, поскольку он переопределен, у меня есть 4 метода с изменением сигнатуры в типе списка):

private void WriteResults(List<InternalLinksModel> results, string filename) { // Logs results into folder to display in jenkins }

private void WriteResults(List<PdfLinksModel> results, string filename) { // Logs results into folder to display in jenkins }

// and so on

РЕДАКТИРОВАТЬ: Добавление дополнительного кода

Интерфейс:

public interface ILinkHandler<T>
{   
    Task<List<T>> Validate();
}

Пример класса обработчика, наследующего интерфейс:

public class InternalLinkHandler : ILinkHandler<InternalLinksModel>
{
    public List<InternalLinksModel> InternalLinks = new List<InternalLinksModel>();

    public async Task<List<InternalLinksModel>> Validate()
    {
        // Here set up my tests, call tasks that modifies InternalLinks List and I await for its results
        return InternalLinks 
    }

Основной класс (с именем XmlLinkCheckerValidator), где мой код выполняется в данный момент (и работает):

public class XmlLinkCheckerValidator
{
    // References to all modes
    public ExternalLinkHandler ExternalLinkHandler => new ExternalLinkHandler();
    public ImageLinkHandler ImageLinkHandler => new ImageLinkHandler();
    public InternalLinkHandler InternalLinkHandler => new InternalLinkHandler();
    public PdfLinkHandler PdfLinkHandler => new PdfLinkHandler();

    public void ValidateIPack()
    {
        InitialSetup();

        Console.WriteLine("Validating External_Links");
        var resultsForExternalLinks = ExternalLinkHandler.Validate();
        WriteResultsForIPacksInCsv(resultsForExternalLinks.Result, "External_Links");

        Console.WriteLine("Validating Image_Links");
        var resultsForImageLinks = ImageLinkHandler.Validate();
        WriteResultsForIPacksInCsv(resultsForImageLinks.Result, "Image_Links");

        Console.WriteLine("Validating Internal_Links");
        var resultsForInternalLinks = InternalLinkHandler.Validate();
        WriteResultsForIPacksInCsv(resultsForInternalLinks.Result, "Internal_Links");

        // Console.WriteLine("Validating Pdf Links");
        // var results = XmlLinkExtractorFromIPacks.PdfLinkHandler.Validate();
        // WriteResultsForIPacks(results, "Pdf Links");
    }

    private void WriteResultsForIPacksInCsv(List<InternalLinksModel> results, string filename) { logging results }

    private void WriteResultsForIPacksInCsv(List<ExternalLinksModel> results, string filename) { logging results }

    private void WriteResultsForIPacksInCsv(List<ImageLinksModel> results, string filename) { logging results }

    private void WriteResultsForIPacksInCsv(List<PdfLinksModel> results, string filename) { logging results }

    private void WriteResultsForIPacksInCsv(List<InternalLinksModel> results, string filename) { logging results }

1 Ответ

0 голосов
/ 28 октября 2019

Я наконец-то реорганизовал весь свой код, и это выглядит очень ясно. Как я уже сказал, вначале, я думаю, что я немного запутался, и все началось с одного неудачного решения, которое я принял.

Короче говоря, я добавил новый метод, WriteResults(string filename). Сделав это, я реализовал метод и удалил переопределенный метод (WriteResultsForIPacksInCsv(List<WhateverModelIHad> results, string filename)) из своего класса «Main». Исходя из этого, я изменил сигнатуру метода Validate в интерфейсе на Task<List<PossibleResults>> Validate(), и, поскольку у каждой модели есть это общее, я удалил универсальный элемент в интерфейсе. Теперь я могу вызывать свои обработчики следующим образом:

public void Validate(ILinkHandler handler, string filename)
{
    Console.WriteLine($"Validating {filename}");
    var results = handler.Validate();
    SetUpResultsStatistics(results.Result, $"{filename}_Statistics");
    handler.WriteResults(filename);
}

Я создал функцию с именем void SetUpResultsStatistics(List<PossibleResults> results, string filename), которая выдает статистику результатов и является общей для всех обработчиков (таким образом, чтобы избежать дублирования, я помещаю ее туда),

Код теперь намного понятнее, и теперь он не использует ни обобщенные, ни переопределенные методы. Мне, однако, все еще интересно, как мне поступить с таким случаем, и я попытаюсь сформулировать его в другом вопросе на гораздо более простом примере.

Спасибо всем за ваши комментарии, очень признателен!

...