如何创建一个返回泛型类型的泛型函数

本文关键字:泛型类型 返回 泛型 函数 一个 何创建 创建 | 更新日期: 2023-09-27 18:03:56

尝试在c#中创建一个通用的lerp函数。我的函数现在看起来像下面这个。

public T Lerp<T>(T lhs, T rhs, float t)
{
    return (1.0f - t) * lhs + t * rhs;
}

作为副本引用的问题将它们的类型限制为内置类型。我不想返回约束,我想返回c#中T类型的对象(泛型对象?)

如何创建一个返回泛型类型的泛型函数

要做到这一点需要几个步骤。我们将删除ref关键字,因为它们在这种情况下没有帮助。假设你想要LERP向量。假设你有一组矢量对象,分别是Vector2、Vector3和Vector4(分别是二维矢量、3d和4d)。要使Lerp函数与所有这三个对象一起工作,您必须首先调整这些对象。

为这三个执行向量和浮点数乘法的基类创建一个。基类调用在特定向量对象中执行实际数学运算的抽象方法。基类看起来像这样:

public abstract BaseVector
{
    public abstract BaseVector Multiply(float multiplier);
    public static BaseVector operator *(BaseVector v, float multiplier)
    {
        return v.Multiply(multiplier);
    }
    // Add the operator * overload where the multiplier is first
}

现在,对于函数本身,问题是提供一个where子句来利用基类的行为。如果你的Vector2、Vector3和Vector4类都扩展了BaseVector并实现了Multiply()方法,那么这将会工作:

public T Lerp<T>(T lhs, T rhs, float t)
    where T : BaseVector
{
    return (1.0f - t) * lhs + t * rhs;
}

不能变得更泛型,因为操作符重载是静态扩展方法,必须在它们应用的类中声明。您可以使用一个接口,然后可以使用实现该接口的任何对象,但是您必须直接调用在接口中声明的Multiply方法。在这种情况下,您可以更改where子句,让T实现接口。语法相同,只是类型从BaseVector变为接口名称。

除非指定where子句,否则不能调用基本Object类型中不存在的对象的方法名。


programmers.stackexchange.com的回答:

如果你的目的是弄清楚如何实现任何传入类型的LERP函数,那么你的问题可能更适合Stackoverflow.com。

由于线性插值通常是用浮点数实现的,所以在这种情况下使用泛型可能是最干净的而不是。结果是一个浮点数:

// Precise method which guarantees v = v1 when t = 1.
public static float Lerp(float v0, float v1, float t)
{
    return (1-t)*v0 + t*v1;
}

如果您认为将所有类型更改为双精度类型是有用的,则可以提高精度。这使得一个简单的函数简单地运行。你会遇到的问题是,操作符重载是静态的,所以如果你想创建一个对多个对象(例如向量)操作的函数,你必须创建一个基类,所有这些对象扩展它定义了operator*重载,并提供一个where子句来限制T扩展该基类。那会很复杂的。

这个答案的重点是让你思考你为什么感觉你:

  1. 需要函数是通用的
  2. 需要ref关键字

都使一个非常简单的函数复杂化。ref关键字是不必要的,因为您只读取参数。在处理数值时,不需要使用泛型,因为在提高精度时,它们都具有隐式转换操作符。当降低精度时,它们也都有显式转换操作符。简而言之,除非您使用的是复杂类型,否则请保持方法非常简单,只有在真正需要时才使用更复杂的技巧。