Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/263.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 帽子,先生。Lippert阐明了一个严酷的事实,即在推理阶段只检查签名的参数,而不检查约束。因此,我们必须在这里更“具体”一点_C#_Generics_Type Parameter - Fatal编程技术网

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