C#使用泛型调用重写方法 [英] C# Use Generics to Call Overridden Method

查看:90
本文介绍了C#使用泛型调用重写方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想我现在有点困惑,但是我似乎无法解决这个问题.

我有一个接口ILinkHandler<T>和其他4个处理程序类(从该接口继承),它们验证链接的不同结构.从该接口,我有一个Task<List<T>> Validate()函数,该函数对链接进行验证并返回结果的Task>.根据T,我在Validate()上返回一个不同的模型(我有4个不同的模型).

我的控制台应用程序执行以下操作.它调用每种链接类型的Task<List<T>> Validate();方法,并在获取结果后创建一些日志(请注意Validate()async).每个日志都有一点不同,因为模型是不同的,所以我覆盖了一个名为WriteResults(ModelX results, string name)的方法,并从ModelX类型(请参见问题末尾,我张贴了2个示例)中,我做了一些不同的事情(对此不重要)范围,但如有必要,我可以提供详细信息.此方法不是异步的.

我想使用泛型和接口创建方法(ValidateModel<T>),该方法处理从模型类型对覆盖方法WriteResults的正确调用,并从接口调用Validate()方法. /p>

下面的代码是我做到的,但是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 }

解决方案

我终于重构了所有代码,看起来很清楚.就像我说的那样,在一开始,我想我有点困惑,这一切都是从我做出的一个错误的设计决定开始的.

简而言之,我添加了一个新方法WriteResults(string filename).这样做,我实现了该方法,并从我的"Main"类中删除了覆盖的方法(WriteResultsForIPacksInCsv(List<WhateverModelIHad> results, string filename)).从那以后,我将接口中的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)的函数,该函数提供结果的统计信息,并且对所有处理程序都是通用的(因此,为避免重复,我将其放在此处).

代码现在更加清晰,并且现在不使用任何泛型或覆盖的方法.但是,我仍然对如何处理这样的情况感到好奇,并会尝试通过一个更简单的示例将其表达在另一个问题中.

谢谢大家的评论,非常感谢!

I think I am a bit mixed up at this point, but I can't seem to be able to solve this issue.

I have an Interface ILinkHandler<T> and 4 other handler classes (inheriting from that interface) that validate different structures of links. From that interface, I have a Task<List<T>> Validate() function that does the validation of links and returns a Task> of results. Depending on T, I return a different model on Validate() (I have 4 different models).

My console app does the following. It calls the Task<List<T>> Validate(); method of every link type and creates some logs after getting results (note that Validate() is async). Every log is a little bit different, since the model is different, so I overrode a method named WriteResults(ModelX results, string name) and from the ModelX type (see end of question, I posted 2 examples), I do some stuff different (not important on this scope I think, but I can provide details if necessary). This method is NOT async.

I wanted to use Generics and my Interface to create a method (ValidateModel<T>) that handles the right call to the overridden method WriteResults from the type of the model and calls the Validate() method from the interface.

The code below is that I did that worked, but the if part resembles what I currently have in my main and I want to avoid.

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
}

Here is what I have in my main:

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
}

I want more something like this if possible, but this does not compile:

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);
}

Here is the definition of WriteResults (note that since it's overridden, I have 4 methods with their signature changing in the type of the list):

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

EDIT: Adding more code

Interface:

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

Example of Handler Class inheriting the interface:

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 
    }

Main Class (named XmlLinkCheckerValidator) where my code runs currently (and it works):

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 }

解决方案

I finally refactored all my code and it looks much clear. As I said, in the beginning, I think I got a bit mixed up and it all started from one bad design decision I took.

In short, I added a new method, WriteResults(string filename). Doing so, I implemented the method and removed the overridden method (WriteResultsForIPacksInCsv(List<WhateverModelIHad> results, string filename)) from my "Main" class. From that, I changed the Validate method signature in the interface to Task<List<PossibleResults>> Validate() and since every model has that in common, I removed the generic in the interface. I can now call my handlers the following way:

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

I created a function named void SetUpResultsStatistics(List<PossibleResults> results, string filename) which gives statistics of results and it is common to all handlers (thus, to avoid duplication I put it there).

Code is now much clearer and it now does not use any generics nor overridden method. I, however, am still curious as to how should I handle a case like that and will try to formulate it in another question with a much simpler example.

Thank you all for your comments, really appreciated!

这篇关于C#使用泛型调用重写方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆