[英]Too many generics in C#
我正在編寫一個用於數學優化的算法,並且面臨大量泛型參數的問題。 有解決方案、問題、算子和算法。 每個都有自己的接口結構,因此可以用新的類進行擴展。 使用在 Main function 中創建變異算子 NonUniform 的示例,我展示了其創建的復雜性。 如果您很少創建此類對象,這不是問題,但是有許多類似的運算符,並且對於每個,您需要列出所有通用參數,並且它們也會重復。 我嘗試將這些參數傳遞給方法,但是在 inheritance 期間,無法指定更嚴格的限制。 如何擺脫這么多的generics? 也許值得修改架構,或者有一些我不知道的語言機制。
#region Algorithms
interface IAlgorithm<out TProblem, out TSolution>
where TProblem : IProblem<TSolution>
where TSolution : ISolution
{
Random Random { get; }
TProblem Problem { get; }
TSolution Best { get; }
}
interface IIterativeAlgorithm<out TProblem, out TSolution>
: IAlgorithm<TProblem, TSolution>
where TProblem : IProblem<TSolution>
where TSolution : ISolution
{
int CurrentIteration { get; }
}
class IterativeAlgorithm<TProblem, TSolution>
: IIterativeAlgorithm<TProblem, TSolution>
where TProblem : IProblem<TSolution>
where TSolution : ISolution
{
public Random Random { get; }
public TProblem Problem { get; }
public TSolution Best { get; }
public int CurrentIteration { get; }
}
#endregion
#region Operator
interface IOperator<in TAlgorithm, TProblem, TSolution>
where TAlgorithm : IAlgorithm<TProblem, TSolution>
where TProblem : IProblem<TSolution>
where TSolution : ISolution
{
public void SetAlgorithm(TAlgorithm algorithm);
}
interface ICoordinateMutator<in TAlgorithm, TFunction, TPoint>
: IOperator<TAlgorithm, TFunction, TPoint>
where TAlgorithm : IAlgorithm<TFunction, TPoint>
where TFunction : IFunction<TPoint>
where TPoint : IPoint
{
void MutateCoordinates(TPoint point);
}
abstract class CoordinateMutator<TAlgorithm, TFunction, TPoint>
: ICoordinateMutator<TAlgorithm, TFunction, TPoint>
where TAlgorithm : IAlgorithm<TFunction, TPoint>
where TFunction : IFunction<TPoint>
where TPoint : IPoint
{
protected Func<Random> GetRandom { get; set; }
public CoordinateMutator()
{
GetRandom = null;
}
public virtual void SetAlgorithm(TAlgorithm algorithm)
{
GetRandom = () => algorithm.Random;
}
public abstract void MutateCoordinates(TPoint point);
}
class NonUniform<TIterativeAlgorithm, TFunction, TPoint> :
CoordinateMutator<TIterativeAlgorithm, TFunction, TPoint>
where TIterativeAlgorithm : IIterativeAlgorithm<TFunction, TPoint>
where TFunction : IFunction<TPoint>
where TPoint : IPoint
{
private Func<int> GetCurrentIteration { get; set; }
private Func<double[]> GetLowerSearchBorder { get; set; }
private Func<double[]> GetUpperSearchBorder { get; set; }
public override void SetAlgorithm(TIterativeAlgorithm algorithm)
{
base.SetAlgorithm(algorithm);
GetCurrentIteration = () => algorithm.CurrentIteration;
GetLowerSearchBorder = () => algorithm.Problem.LowerSearchBorders;
GetUpperSearchBorder = () => algorithm.Problem.UpperSearchBorders;
}
public override void MutateCoordinates(TPoint point)
{
Random random = GetRandom();
double currentIteration = GetCurrentIteration();
double[] lowerSearchBorders = GetLowerSearchBorder();
double[] upperSearchBorders = GetUpperSearchBorder();
throw new NotImplementedException("TODO");
}
}
#endregion
#region Problems
interface IProblem<in TSolution>
where TSolution : ISolution
{
}
interface IFunction<in TPoint>
: IProblem<TPoint>
where TPoint : IPoint
{
double[] LowerSearchBorders { get; }
double[] UpperSearchBorders { get; }
}
abstract class Function<TPoint>
: IFunction<TPoint>
where TPoint : IPoint
{
public double[] LowerSearchBorders { get; }
public double[] UpperSearchBorders { get; }
}
class Sphere<TPoint>
: Function<TPoint>
where TPoint : IPoint
{
public double GetValueOf(TPoint solution) => throw new NotImplementedException("TODO");
}
#endregion
#region Solutions
interface ISolution
{
}
interface IPoint : ISolution
{
}
class Point : IPoint
{
}
#endregion
private static void Main()
{
var cm = new NonUniform<IterativeAlgorithm<Function<Point>, Point>, Function<Point>, Point>();
}
我認為您擁有太多 generics 的主要原因之一來自ICopy<T>
接口。
您可以將其設為非泛型並使 Copy 方法返回 object。 或者改用 IClonable 接口。 它會減少其他接口和類的泛型參數,但每次調用 Copy 方法時都需要對其結果進行強制轉換。
另一種選擇是使用 C# 9 和 .NET 5 的協變返回功能
當接口繼承 ICopy 時,它不必是通用的
interface ISolution : ICopy<ISolution>
{
}
interface IPoint : ISolution
{
}
您需要聲明一個抽象的 class 實現接口:
abstract class PointBase : IPoint
{
public abstract ISolution Copy();
}
然后,您可以使用協變返回來實現具有更具體類型的 Copy 方法
class Point : PointBase
{
public override Point Copy() => new Point();
}
據我所知,不需要 generics。 例如
interface ISolution
{
}
這是干什么用的? 它沒有屬性或方法,所以我無法對解決方案做任何事情。 唯一的用法似乎是作為標記,例如依賴注入/反射,但您似乎沒有以這種方式使用它。
另一個例子是方法
public override void MutateCoordinates(TPoint point)
{
Random random = GetRandom();
double currentIteration = GetCurrentIteration();
double[] lowerSearchBorders = GetLowerSearchBorder();
double[] upperSearchBorders = GetUpperSearchBorder();
throw new NotImplementedException("TODO");
}
我們知道那個點是一個IPoint
,它是一個ISolution
。 但那又怎樣? 我們不能將點用於任何事情,因為它沒有屬性或方法,“TODO”很方便地省略了一些東西。 我們可以將float X {get;} float Y {get;}
之類的屬性添加到接口以允許實際使用,但我們也可以使用方法簽名
public override void MutateCoordinates(IPoint point)
使用 generics 的一個可能原因是它可能允許更多優化,但代價是更大的代碼大小。 如果您在點數百萬次上調用方法,這可能與點之類的東西相關,但可能與IAlgorithm
等更高級別的概念無關。 分析和/或基准測試應該顯示這是否相關。 標准建議是從最簡單的解決方案開始。
我會考慮修改您的結構並刪除 generics 與常規類型的所有用法。 為這樣的領域創建一個好的描述可能非常困難,而且如果沒有更多信息,很難提供好的建議。 generics 可能是某種建模的最佳解決方案。 但是,如示例所示,用泛型類型替換所有類型可能不是 go 的方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.