有没有办法在另一个抽象 class 中使用抽象泛型 class?
Is there a way to use an abstract generic class within another abstract class?
这个问题的措辞可能没有我想要的那么好,但我一直在努力做的是:
我有一个 运行 的应用程序并显示我从 TopCoder 解决的问题的结果。
由于所有这些问题都遵循相同的格式(接受一些输入,做某事,将输出与正确答案进行比较)我试图将通用功能收集到一个抽象的 class 问题中。
这是一个简化版:
public abstract class Problem
{
// Some public fields and tasks exist here
// Some protected methods for reporting progress exist here
// Some abstract fields for things like the problem name and the link to the problem page exist here
#region Abstract Methods
protected abstract void RunExamplesOnce(CancellationToken token, IProgress<int> progress = null);
protected abstract void RunExamplesForAverage(CancellationToken token, IProgress<int> progress = null);
#endregion
#region Example Class
protected abstract class Example<T1, T2>
{
public T1 Inputs;
public T2 CorrectOutput;
public Example(T1 inputs, T2 correctOutput)
{
this.Inputs = inputs;
this.CorrectOutput = correctOutput;
}
public abstract (bool Pass, long ElapsedMilliseconds) TestExample();
}
#endregion
}
然后我为每个问题创建一个 class,例如TestProblem :问题并酌情覆盖。
我还创建了适当的 TestExample:示例,它将指定这些输入和输出的类型,并在 TestProblem 中创建这些输入和输出的数组。
到目前为止这一切都有效,但每次都会重复 RunExamplesOnce 和 RunExamplesForAverage 中的许多功能。
这些函数将始终采用示例,遍历它们 运行 一个始终 return bool Pass 和 long ElapsedMilliseconds 的函数,并用这些结果更新显示的文本。
protected override void RunExamplesOnce(CancellationToken token, IProgress<int> progress = null)
{
answer = "";
List<bool> passesForEachExample = new List<bool>();
List<long> timesElapsedForEachExample = new List<long>();
for (int i = 0; i < examples.Length; i++)
{
// Stop if cancelled
if (token.IsCancellationRequested)
{
answer = $"{Name} cancelled\r\n";
return;
}
// Report Progress
ReportProgress(i, examples.Length, progress);
// Perform code
var (Pass, ElapsedMilliseconds) = examples.ElementAt(i).TestExample();
answer += $"Example {i}: Pass {Pass} in {ElapsedMilliseconds} ms\r\n";
passesForEachExample.Add(Pass);
timesElapsedForEachExample.Add(ElapsedMilliseconds);
}
ReportProgress(100, progress);
answer += $"Overall Pass {passesForEachExample.All(c => c = true)} in {timesElapsedForEachExample.Sum()} ms\r\n\r\n";
}
我的看法 - 该函数不关心输入或输出类型是什么。它只需要将一个 Example 传递给 TestExample() ,它将始终被适当地覆盖。
有没有什么方法可以在抽象 class 问题中使用未定义的泛型 Example (这似乎不起作用)来定义函数,或者改变我如何构造这些函数的方法 class是否可以达到相同的结果?
编辑:
感谢您的回答!我最终采纳了 Legacy Code 的建议,这非常适合我想做的事情。如果有人好奇,代码在我的 GitHub 上,现在位于 elysiara/TopCoder。
如果 Problem
class 包含示例,那么您可以在其中实现 RunExamplesOnce
并提供使用 virtual
更改该实现的能力。
抽象 classes 可以包含具有实现的方法,这样您就不会重复代码。
public abstract class Problem
{
// Some public fields and tasks exist here
// Some protected methods for reporting progress exist here
// Some abstract fields for things like the problem name and the link to the problem page exist here
protected virtual void RunExamplesOnce(CancellationToken token, IProgress<int> progress = null)
{
answer = "";
List<bool> passesForEachExample = new List<bool>();
List<long> timesElapsedForEachExample = new List<long>();
for (int i = 0; i < examples.Length; i++)
{
// Stop if cancelled
if (token.IsCancellationRequested)
{
answer = $"{Name} cancelled\r\n";
return;
}
// Report Progress
ReportProgress(i, examples.Length, progress);
// Perform code
var (Pass, ElapsedMilliseconds) = examples.ElementAt(i).TestExample();
answer += $"Example {i}: Pass {Pass} in {ElapsedMilliseconds} ms\r\n";
passesForEachExample.Add(Pass);
timesElapsedForEachExample.Add(ElapsedMilliseconds);
}
ReportProgress(100, progress);
answer += $"Overall Pass {passesForEachExample.All(c => c = true)} in {timesElapsedForEachExample.Sum()} ms\r\n\r\n";
}
protected abstract void RunExamplesForAverage(CancellationToken token, IProgress<int> progress = null);
}
RunExamplesForAverage
也是如此。
话又说回来,如果你的抽象 class 真的没有任何它 children 需要实现的东西,你真的需要它吗?
为您的 example
摘要添加一个接口 class
protected abstract class ExampleBase<T1, T2> : IExample
{
public T1 Inputs;
public T2 CorrectOutput;
public Example(T1 inputs, T2 correctOutput)
{
this.Inputs = inputs;
this.CorrectOutput = correctOutput;
}
public abstract (bool Pass, long ElapsedMilliseconds) TestExample();
}
public interface IExample
{
(bool Pass, long ElapsedMilliseconds) TestExample();
}
然后您必须将 examples
array/list/collection 的元素类型更改为 IExample
。
之后,您可以在 Problem
基础 class.
中使用 RunExamplesOnce
方法
这个问题的措辞可能没有我想要的那么好,但我一直在努力做的是:
我有一个 运行 的应用程序并显示我从 TopCoder 解决的问题的结果。 由于所有这些问题都遵循相同的格式(接受一些输入,做某事,将输出与正确答案进行比较)我试图将通用功能收集到一个抽象的 class 问题中。
这是一个简化版:
public abstract class Problem
{
// Some public fields and tasks exist here
// Some protected methods for reporting progress exist here
// Some abstract fields for things like the problem name and the link to the problem page exist here
#region Abstract Methods
protected abstract void RunExamplesOnce(CancellationToken token, IProgress<int> progress = null);
protected abstract void RunExamplesForAverage(CancellationToken token, IProgress<int> progress = null);
#endregion
#region Example Class
protected abstract class Example<T1, T2>
{
public T1 Inputs;
public T2 CorrectOutput;
public Example(T1 inputs, T2 correctOutput)
{
this.Inputs = inputs;
this.CorrectOutput = correctOutput;
}
public abstract (bool Pass, long ElapsedMilliseconds) TestExample();
}
#endregion
}
然后我为每个问题创建一个 class,例如TestProblem :问题并酌情覆盖。 我还创建了适当的 TestExample:示例,它将指定这些输入和输出的类型,并在 TestProblem 中创建这些输入和输出的数组。 到目前为止这一切都有效,但每次都会重复 RunExamplesOnce 和 RunExamplesForAverage 中的许多功能。 这些函数将始终采用示例,遍历它们 运行 一个始终 return bool Pass 和 long ElapsedMilliseconds 的函数,并用这些结果更新显示的文本。
protected override void RunExamplesOnce(CancellationToken token, IProgress<int> progress = null)
{
answer = "";
List<bool> passesForEachExample = new List<bool>();
List<long> timesElapsedForEachExample = new List<long>();
for (int i = 0; i < examples.Length; i++)
{
// Stop if cancelled
if (token.IsCancellationRequested)
{
answer = $"{Name} cancelled\r\n";
return;
}
// Report Progress
ReportProgress(i, examples.Length, progress);
// Perform code
var (Pass, ElapsedMilliseconds) = examples.ElementAt(i).TestExample();
answer += $"Example {i}: Pass {Pass} in {ElapsedMilliseconds} ms\r\n";
passesForEachExample.Add(Pass);
timesElapsedForEachExample.Add(ElapsedMilliseconds);
}
ReportProgress(100, progress);
answer += $"Overall Pass {passesForEachExample.All(c => c = true)} in {timesElapsedForEachExample.Sum()} ms\r\n\r\n";
}
我的看法 - 该函数不关心输入或输出类型是什么。它只需要将一个 Example 传递给 TestExample() ,它将始终被适当地覆盖。
有没有什么方法可以在抽象 class 问题中使用未定义的泛型 Example
编辑:
感谢您的回答!我最终采纳了 Legacy Code 的建议,这非常适合我想做的事情。如果有人好奇,代码在我的 GitHub 上,现在位于 elysiara/TopCoder。
如果 Problem
class 包含示例,那么您可以在其中实现 RunExamplesOnce
并提供使用 virtual
更改该实现的能力。
抽象 classes 可以包含具有实现的方法,这样您就不会重复代码。
public abstract class Problem
{
// Some public fields and tasks exist here
// Some protected methods for reporting progress exist here
// Some abstract fields for things like the problem name and the link to the problem page exist here
protected virtual void RunExamplesOnce(CancellationToken token, IProgress<int> progress = null)
{
answer = "";
List<bool> passesForEachExample = new List<bool>();
List<long> timesElapsedForEachExample = new List<long>();
for (int i = 0; i < examples.Length; i++)
{
// Stop if cancelled
if (token.IsCancellationRequested)
{
answer = $"{Name} cancelled\r\n";
return;
}
// Report Progress
ReportProgress(i, examples.Length, progress);
// Perform code
var (Pass, ElapsedMilliseconds) = examples.ElementAt(i).TestExample();
answer += $"Example {i}: Pass {Pass} in {ElapsedMilliseconds} ms\r\n";
passesForEachExample.Add(Pass);
timesElapsedForEachExample.Add(ElapsedMilliseconds);
}
ReportProgress(100, progress);
answer += $"Overall Pass {passesForEachExample.All(c => c = true)} in {timesElapsedForEachExample.Sum()} ms\r\n\r\n";
}
protected abstract void RunExamplesForAverage(CancellationToken token, IProgress<int> progress = null);
}
RunExamplesForAverage
也是如此。
话又说回来,如果你的抽象 class 真的没有任何它 children 需要实现的东西,你真的需要它吗?
为您的 example
摘要添加一个接口 class
protected abstract class ExampleBase<T1, T2> : IExample
{
public T1 Inputs;
public T2 CorrectOutput;
public Example(T1 inputs, T2 correctOutput)
{
this.Inputs = inputs;
this.CorrectOutput = correctOutput;
}
public abstract (bool Pass, long ElapsedMilliseconds) TestExample();
}
public interface IExample
{
(bool Pass, long ElapsedMilliseconds) TestExample();
}
然后您必须将 examples
array/list/collection 的元素类型更改为 IExample
。
之后,您可以在 Problem
基础 class.
RunExamplesOnce
方法