首页 > 解决方案 > C#泛型方法选择

问题描述

我正在尝试用 C# 编写可以处理不同维度几何实体的通用算法。

在下面的人为示例中,我有Point2Point3,它们都实现了一个简单的IPoint接口。

现在我有一个GenericAlgorithm调用函数的函数GetDim。该函数根据类型有多种定义。还有一个为任何实现IPoint.

我最初预计以下程序的输出是 2、3。但是,它是 0、0。

interface IPoint {
    public int NumDims { get; } 
}

public struct Point2 : IPoint {
    public int NumDims => 2;
}

public struct Point3 : IPoint {
    public int NumDims => 3;
}

class Program
{
    static int GetDim<T>(T point) where T: IPoint => 0;
    static int GetDim(Point2 point) => point.NumDims;
    static int GetDim(Point3 point) => point.NumDims;

    static int GenericAlgorithm<T>(T point) where T : IPoint => GetDim(point);

    static void Main(string[] args)
    {
        Point2 p2;
        Point3 p3;
        int d1 = GenericAlgorithm(p2);
        int d2 = GenericAlgorithm(p3);
        Console.WriteLine("{0:d}", d1);        // returns 0 !!
        Console.WriteLine("{0:d}", d2);        // returns 0 !!
    }
}

好的,所以由于某种原因,具体类型信息丢失在GenericAlgorithm. 我不完全理解为什么会发生这种情况,但是很好。如果我不能这样做,我还有什么其他选择?

标签: c#generics

解决方案


这种方法:

static int GenericAlgorithm<T>(T point) where T : IPoint => GetDim(point);

……总会打电话GetDim<T>(T point)的。重载决议是在编译时执行的,在那个阶段没有其他适用的方法。

如果你想在执行时调用重载决议,你需要使用动态类型,例如

static int GenericAlgorithm<T>(T point) where T : IPoint => GetDim((dynamic) point);

但是为此使用继承通常是一个更好的主意-在您的示例中,显然您可以只使用单个方法和 return point.NumDims。我假设在您的真实代码中,有一些原因等效于做起来比较棘手,但是如果没有更多上下文,我们无法建议如何使用继承来执行专业化。这些是您的选择:

  • 基于目标的执行时类型的专门化的继承(首选)
  • 执行时重载解决方案的动态类型

推荐阅读