C# 帽子,先生。Lippert阐明了一个严酷的事实,即在推理阶段只检查签名的参数,而不检查约束。因此,我们必须在这里更“具体”一点
首先,让我们来定义我们的“二元关系”——我应该注意到这是建立这些关系的一种方式,理论上有无限的多样性C# 帽子,先生。Lippert阐明了一个严酷的事实,即在推理阶段只检查签名的参数,而不检查约束。因此,我们必须在这里更“具体”一点,c#,generics,type-parameter,C#,Generics,Type Parameter,首先,让我们来定义我们的“二元关系”——我应该注意到这是建立这些关系的一种方式,理论上有无限的多样性 public interface IDual<TPoint, TDualPoint> where TPoint: IPoint<TPoint>, IDual<TPoint, TDualPoint> where TDualPoint: IPoint<TDualPoint>, IDual<TDualPoint, TPoint&g
public interface IDual<TPoint, TDualPoint>
where TPoint: IPoint<TPoint>, IDual<TPoint, TDualPoint>
where TDualPoint: IPoint<TDualPoint>, IDual<TDualPoint, TPoint>
{}
公共接口个人
其中t点:i点,个人
其中TDualPoint:i点,个人
{}
现在,我们返回并改进现有签名:
public interface IPoint<TPoint>
where TPoint:IPoint<TPoint>
{}
class TriPoint : IPoint<TriPoint>, IDual<TriPoint,HexPoint>
{}
class HexPoint : IPoint<HexPoint>, IDual<HexPoint,TriPoint>
{
// Normally you would rotate the point
public HexPoint Rotate240(){ return new HexPoint();}
}
公共接口IPoint
其中TPoint:IPoint
{}
类三点:i点,个体
{}
类六角点:i点,单个
{
//通常你会旋转这个点
公共六角点旋转240(){返回新六角点();}
}
同样,在“次要类型”上,网格:
interface IGrid<TPoint, TDualPoint>
where TPoint: IPoint<TPoint>, IDual<TPoint, TDualPoint>
where TDualPoint : IPoint<TDualPoint>, IDual<TDualPoint, TPoint>
{
TDualPoint GetDualPoint(TPoint point);
}
class HexGrid : IGrid<HexPoint, TriPoint>
{
public TriPoint GetDualPoint(HexPoint point)
{
return new TriPoint();
}
}
class TriGrid : IGrid<TriPoint, HexPoint>
{
public HexPoint GetDualPoint(TriPoint point)
{
return new HexPoint();
}
}
接口IGrid
其中t点:i点,个人
其中TDualPoint:i点,个人
{
TDualPoint GetDualPoint(TPoint点);
}
类:IGrid
{
公共三点GetDualPoint(六点)
{
返回新的三点();
}
}
类TriGrid:IGrid
{
公共六角点GetDualPoint(三点)
{
返回新的六角点();
}
}
最后是我们的实用方法:
static class Algorithms
{
public static IEnumerable<TPoint> TransformShape<TPoint, TDualPoint>(
IEnumerable<IDual<TPoint, TDualPoint>> shape,
Func<TPoint, TPoint> transform)
where TPoint : IPoint<TPoint>, IDual<TPoint, TDualPoint>
where TDualPoint : IPoint<TDualPoint>, IDual<TDualPoint, TPoint>
{
return
from TPoint point in shape
select transform(point);
}
public static IEnumerable<TPoint> TransformShape<TPoint, TDualPoint>(
IGrid<TPoint, TDualPoint> grid,
IEnumerable<IDual<TPoint, TDualPoint>> shape,
Func<TPoint, TPoint> transform)
where TPoint : IPoint<TPoint>, IDual<TPoint, TDualPoint>
where TDualPoint : IPoint<TDualPoint>, IDual<TDualPoint, TPoint>
{
return
from TPoint point in shape
//where transform(point) is in grid
select transform(point);
}
}
静态类算法
{
公共静态IEnumerable TransformShape(
数不清的形状,
Func变换)
其中t点:i点,个人
其中TDualPoint:i点,个人
{
返回
从形状上的点开始
选择变换(点);
}
公共静态IEnumerable TransformShape(
IGrid网格,
数不清的形状,
Func变换)
其中t点:i点,个人
其中TDualPoint:i点,个人
{
返回
从形状上的点开始
//变换(点)在栅格中的位置
选择变换(点);
}
}
注意方法上的签名-我们说“嘿,我们给你的东西列表,它绝对有两点”,这就是允许这样的代码的原因:
HexGrid hexGrid = new HexGrid();
List<HexPoint> hexPointShape = new List<HexPoint>(); //Add some items
//Compiles
var rotatedShape1 = Algorithms
.TransformShape(
hexGrid,
hexPointShape,
point => point.Rotate240())
.ToList();
//Compiles
var rotatedShape2 = Algorithms
.TransformShape<HexPoint, TriPoint>(
hexPointShape,
point => point.Rotate240())
.ToList();
//Did not compile, but does now!
var rotatedShape3 = Algorithms
.TransformShape(
hexPointShape,
point => point.Rotate240())
.ToList();
HexGrid HexGrid=new HexGrid();
List hexPointShape=新列表()//添加一些项目
//汇编
var rotatedShape1=算法
.变形金刚(
hexGrid,
六角形,
point=>point.Rotate240()
.ToList();
//汇编
var rotatedShape2=算法
.变形金刚(
六角形,
point=>point.Rotate240()
.ToList();
//没有编译,但现在编译!
var rotatedShape3=算法
.变形金刚(
六角形,
point=>point.Rotate240()
.ToList();
据我所知,您当前的版本可能不起作用-HexGrid.GetDualGrid()的返回类型是一个IGrid
-不能隐式转换为TriGrid
。对于IGrid
,您已经需要第三个类型参数。谢谢,错误出现在“简化”中。我更正了代码和解释(但现在这个示例似乎有点弱)。我希望能够这样工作(这实际上是整个问题的另一个例子…)您提到,CalcShortestPath
要求客户知道HexPoint
的双点是TriPoint
,但这真的是这样吗?类型推断应该允许您在完全没有类型参数的情况下调用CallShortestPath
。编译器将根据传递给它的参数推断适当的类型。您实际有多少点或网格类型?这通常是一个“设计”问题——你可能对泛型做得太多了,我支持@jeanhomial所说的大部分内容。所以,我想你应该问自己一个问题,你真的需要所有的参数都是泛型的吗?也就是说,你是否有无限的或数百(几十)个这样的类型。如果没有-你需要把它分解成什么重要,什么不重要,在需要的地方使用更多好的旧OO+泛型。如果“是”,那么你有一个复杂的系统,同样,需要一些重构。只是一个随机的想法(在一个头痛的模糊的浏览之后),但是添加一个表示对偶的接口会有帮助吗?像IDual一样,TriPoint将在何处实现IDual等?谢谢您的回答。我不能很快确定这是否可行,但这绝对是一件值得考虑的事情。对我来说,最重要的特性是使用库应该简单,客户端代码应该清晰(并且“安全”/“正确”)。你的回答也让我想到了将通用算法转移到网格类的可能性(如果需要的话,他们可以调用通用算法)…+1-一个很好的设计推断-尽管我很确定你不需要背后的一记耳光:)@NSGaga-Aww,我接受我能得到的任何自我提升是的,它工作得很好:)如果这个想法更进一步,我们可以将GetDualPoint
方法移动到IDualGrid
接口中,然后如果实用程序方法中没有使用dual,就可以去掉它们中的其他类型参数。这大大降低了声明的复杂性。它还允许IGrid
的实现者在需要使用的算法不需要时实现双重方法。
interface IGrid<TPoint>
where TPoint:IPoint<TPoint>
//and TPoint has "property" DualPoint where DualPoint implements IPoint...
{
IGrid<TPoint.DualPoint> GetDualGrid();
}
static List<TPoint> CalcShortestPath<TPoint>(
IGrid<TPoint> grid,
TPoint start,
TPoint goal)
{...}
using System;
using System.Collections.Generic;
using System.Linq;
public interface IPoint<TPoint, TDualPoint>
where TPoint:IPoint<TPoint, TDualPoint>
where TDualPoint : IPoint<TDualPoint, TPoint>{}
interface IGrid<TPoint, TDualPoint>
where TPoint:IPoint<TPoint, TDualPoint>
where TDualPoint:IPoint<TDualPoint, TPoint>{}
class HexPoint : IPoint<HexPoint, TriPoint>
{
public HexPoint Rotate240(){ return new HexPoint();} //Normally you would rotate the point
}
class TriPoint : IPoint<TriPoint, HexPoint>{}
class HexGrid : IGrid<HexPoint, TriPoint>{}
static class Algorithms
{
public static IEnumerable<TPoint> TransformShape<TPoint, TDualPoint>(
IEnumerable<TPoint> shape,
Func<TPoint, TPoint> transform)
where TPoint : IPoint<TPoint, TDualPoint>
where TDualPoint : IPoint<TDualPoint, TPoint>
{
return
from TPoint point in shape
select transform(point);
}
public static IEnumerable<TPoint> TransformShape<TPoint, TDualPoint>(
IGrid<TPoint, TDualPoint> grid,
IEnumerable<TPoint> shape,
Func<TPoint, TPoint> transform)
where TPoint : IPoint<TPoint, TDualPoint>
where TDualPoint : IPoint<TDualPoint, TPoint>
{
return
from TPoint point in shape
//where transform(point) is in grid
select transform(point);
}
}
class UserCode
{
public static void UserMethod()
{
HexGrid hexGrid = new HexGrid();
List<HexPoint> hexPointShape = new List<HexPoint>(); //Add some items
//Compiles
var rotatedShape1 = Algorithms.TransformShape(
hexGrid,
hexPointShape,
point => point.Rotate240()).ToList();
//Compiles
var rotatedShape2 = Algorithms.TransformShape<HexPoint, TriPoint>(
hexPointShape,
point => point.Rotate240()).ToList();
//Does not compile
var rotatedShape3 = Algorithms.TransformShape(
hexPointShape,
point => point.Rotate240()).ToList();
}
}
interface IPoint
{
int X {get;}
int Y {get;}
// Maybe you do not need that one.
IPoint Translate(IPoint dual);
}
interface IPoint<TPoint> : IPoint
where TPoint : IPoint<TPoint>
{
new TPoint Translate(TPoint dual);
}
public interface IDual<TPoint, TDualPoint>
where TPoint: IPoint<TPoint>, IDual<TPoint, TDualPoint>
where TDualPoint: IPoint<TDualPoint>, IDual<TDualPoint, TPoint>
{}
public interface IPoint<TPoint>
where TPoint:IPoint<TPoint>
{}
class TriPoint : IPoint<TriPoint>, IDual<TriPoint,HexPoint>
{}
class HexPoint : IPoint<HexPoint>, IDual<HexPoint,TriPoint>
{
// Normally you would rotate the point
public HexPoint Rotate240(){ return new HexPoint();}
}
interface IGrid<TPoint, TDualPoint>
where TPoint: IPoint<TPoint>, IDual<TPoint, TDualPoint>
where TDualPoint : IPoint<TDualPoint>, IDual<TDualPoint, TPoint>
{
TDualPoint GetDualPoint(TPoint point);
}
class HexGrid : IGrid<HexPoint, TriPoint>
{
public TriPoint GetDualPoint(HexPoint point)
{
return new TriPoint();
}
}
class TriGrid : IGrid<TriPoint, HexPoint>
{
public HexPoint GetDualPoint(TriPoint point)
{
return new HexPoint();
}
}
static class Algorithms
{
public static IEnumerable<TPoint> TransformShape<TPoint, TDualPoint>(
IEnumerable<IDual<TPoint, TDualPoint>> shape,
Func<TPoint, TPoint> transform)
where TPoint : IPoint<TPoint>, IDual<TPoint, TDualPoint>
where TDualPoint : IPoint<TDualPoint>, IDual<TDualPoint, TPoint>
{
return
from TPoint point in shape
select transform(point);
}
public static IEnumerable<TPoint> TransformShape<TPoint, TDualPoint>(
IGrid<TPoint, TDualPoint> grid,
IEnumerable<IDual<TPoint, TDualPoint>> shape,
Func<TPoint, TPoint> transform)
where TPoint : IPoint<TPoint>, IDual<TPoint, TDualPoint>
where TDualPoint : IPoint<TDualPoint>, IDual<TDualPoint, TPoint>
{
return
from TPoint point in shape
//where transform(point) is in grid
select transform(point);
}
}
HexGrid hexGrid = new HexGrid();
List<HexPoint> hexPointShape = new List<HexPoint>(); //Add some items
//Compiles
var rotatedShape1 = Algorithms
.TransformShape(
hexGrid,
hexPointShape,
point => point.Rotate240())
.ToList();
//Compiles
var rotatedShape2 = Algorithms
.TransformShape<HexPoint, TriPoint>(
hexPointShape,
point => point.Rotate240())
.ToList();
//Did not compile, but does now!
var rotatedShape3 = Algorithms
.TransformShape(
hexPointShape,
point => point.Rotate240())
.ToList();