C#使用泛型调用重写方法 [英] C# Use Generics to Call Overridden Method
问题描述
我想我现在有点困惑,但是我似乎无法解决这个问题.
我有一个接口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屋!