c# generic class: 如何限制成员函数与特定类型一起使用?

c# generic class: how can I restrict a member function to be used with specific types?

我有一个泛型 class CGeometryCalibration2D<T>,它可以用于 intdoublefloat 等数字类型,以及我的自定义类型 CLocation.
(不太重要)问题 1:如何将 T 限制为这些类型之一?

在这个class里面,有一个函数

double InterpolateReverse (T i_Value);

只能与 CLocation 一起使用,如 T

我不知道有什么方法可以应用这样的限制。
我已经尝试过扩展方法,它会做这个限制

double InterpolateReverse (this CGeometricCalibration2D<CLocation>, CLocation i_Value);

但他们不允许访问私人成员。我可以通过使用反射来解决这个限制,但这不是最好的方法。

我可以在这里做什么?
我是否应该找到一种完全不同的方法?

我剩下的唯一想法是通过具体实现重载通用 class 并在其中添加函数,例如

CGeometricCalibration2D_CLocation : CGeometricCalibration2D<CLocation>
{
  double InterpolateReverse (CLocation i_Value);
}

但是我需要一个具体类型的对象 CGeometricCalibration2D_CLocation 才能执行 InterpolateReverse ()

您可以通过在该方法上定义额外的类型参数并添加类型约束来实现它。为此,您需要创建 ICLocation 接口

public class CGeometryCalibration2D<T> where T: struct
{
    public double InterpolateReverse<V>(V i_Value) where V: struct, ICLocation
    {
        return default(double);
    }
}

public interface ICLocation { }

public struct CLocation : ICLocation { }

用法示例:

var geoInt = new CGeometryCalibration2D<int>();
geoInt.InterpolateReverse(12); //Compile time error
var loc = new CLocation();
geoInt.InterpolateReverse(loc);

您不能对泛型参数设置值类型约束,如 documented here

您可以做的是创建函数的重载而不是使用泛型,例如

double InterpolateReverse (int i_Value);
double InterpolateReverse (double i_Value);
double InterpolateReverse (float i_Value);

对于第一个问题,一个泛型参数不能使用多种类型。想想看。在这种情况下,编译器将如何决定参数的编译时类型?您应该为每个要支持的类型使用重载方法,并简单地删除该通用参数。

这应该也能解决您的第二个问题。

I have a generic class CGeometryCalibration2D<T> which can be used with numeric types like int, double, float, and my custom type CLocation.

这听起来不像是泛型。

how can I restrict T to one of these types.

你不能,没有包含这些类型的约束。

Inside this class there is a function (...) that should only be used with CLocation as T.

简单,不要使方法通用,因为它不是。只需用 CLocation 参数写一个单一的霸主。

记住,泛型意味着泛型。泛型 class 或方法应该能够使用无限组泛型类型参数。当有效类型有限时,您可能做错了什么。

谢谢大家的回答和评论!
考虑之后,我决定将泛型与继承混合使用,希望这是解决我的问题的最干净的方法。
抽象泛型基 class 包含适用于所有可用类型 T 的所有内容,但它不可实例化。具体的实现确保只有那些 T 是可用的,这些 T 是有意义的。

public abstract class CGeometryCalibration2D<T> : CGeometryCalibration<T>
{
  ctor()
  public override void Clear ()
  public bool Add (double i_dPosition, CGeometryCalibration1D<T> i_oGeoCalib1D)
  public bool Remove (double i_dPosition)
  public override void CopyTo (ref CGeometryCalibration<T> io_oGeoCalib)
  public override T Interpolate (CLocation i_locPosition, bool i_bExtrapolate = false)
  public T Interpolate (double i_dPosition, double i_dPositionGC1D, bool i_bExtrapolate = false)
  public override CResulT Load (CXmlDocReader i_xmldocreader)
  public override CResulT Save (CXmlDocWriter i_xmldocwriter)
}

public class CGeometryCalibration2D_Double : CGeometryCalibration2D<double>
{
  ctor()
}

public class CGeometryCalibration2D_CLocation : CGeometryCalibration2D<CLocation>
{
  ctor()
  public double InterpolateReverse (CLocation i_locValue, out CLocation o_ValueInterpolated, bool i_bExtrapolate = false)
}