c#泛型函数

本文关键字:函数 泛型 | 更新日期: 2023-09-27 18:05:39

寻求c#泛型方面的帮助。我正在Unity3D中工作,并且正在滚动BiLerp功能,因为Unity3D没有一个。

public Vector3 BiLerp(Vector2 _uv, Vector3 _00, Vector3 _01, Vector3 _10, Vector3 _11)
{
    return _00 * (1 - _uv.x) * (1 - _uv.y) +
           _10 * _uv.x * (1 - _uv.y) +
           _01 * _uv.y * (1 - _uv.x) +
           _11 * _uv.x * _uv.y;
}

但是,我想使这个函数更健壮一点。

  1. 我想让它通用,这样它就可以接受任何类型,可以乘以一个float
  2. 我不确定我是否应该使这个静态。我假设它不使用任何成员变量,那么是的。如果该类存储在静态中,该类将仅用于unity (Matrix2x2)等省略的数学助手。
  3. 在这种情况下c#的const是如何工作的?
  4. 在c++中,我将通过引用传递参数。如果我正确地假设c#已经这样做了吗?ref关键字是另一个黑魔法工具吗?

如果有任何其他建议,请不要客气。我只在c#工作了6个星期,现在可以使用任何建议。

c#泛型函数

  1. 虽然可以通过传递一个执行乘法的委托来实现,但它会慢得多。实际上,我认为你最好写多个重载,而不是。

  2. 是的,你应该,你也应该把它放在一个静态类。(恕我直言!)我本来打算建议你把它作为一个扩展方法,但是经过反思,它有太多的参数,使它变得那么有用。

  3. c# const与c++ const类似,但一般的共识是它们只能是私有的(或者可能是内部的)。

  4. 实际上,Vector2和Vector3是结构体,所以它们是按值传递的。如果您想通过引用传递它们,请使用ref关键字:

    public Vector3 BiLerp(
        ref Vector2 _uv, ref Vector3 _00, ref Vector3 _01,
        ref Vector3 _10, ref Vector3 _11)`
    

然而,这样做只有两个原因(对于结构体):

  1. 因为你想改变传入的原始值

  2. 通过传递一个引用(即c++术语中的指针)来加速。

第一个在您的代码中不适用,第二个对于这样小的结构体似乎没有意义(事实上,所有结构体都应该很小,所以它几乎不适用于设计良好的结构体)。

我想把它变成通用的,这样它就可以接受任何可以乘以浮点数的类型

不幸的是,c#的泛型类型系统不支持这种约束。这是c#团队考虑过的一个经常被要求的特性,但它需要在底层CLR类型系统中做大量的工作。将来有可能实现,但如果我是你,我不会屏息等待那一天。

我不确定我是否应该使它静态。我假设它不使用任何成员变量,那么是的。

是的,让它变成静态的。

如果存储它的类也是静态的,则该类将仅用于数学帮助。

是的。

c#的const在这种情况下是如何工作的?

c# const与c++ const不同;这就简单多了。在c#中,const字段或local只是编译时常量数或字符串的名称,仅此而已。(好吧,你也可以有const的引用类型,但它必须是空的,所以这不是那么有趣。)这里没有你在c#中看到的"这是一个引用,但你不能调用任何改变它的方法"的规则。

最佳实践是首先使所有值类型不可变,因此c++风格的const并不是真正必要的。

将字段标记为"只读"使其只能在构造函数中更改。

在c++中,我将通过引用传递参数。我假设c#已经做到这一点是正确的吗?

。值类型按值传递。

ref关键字是其他一些黑魔法的工具?

ref关键字就像c++中的引用:使一个变量成为另一个的别名。在c#中,您通常只在希望改变调用者提供的变量的情况下使用。正如我之前所说的,c#没有c++的"const引用"的概念,但是由于c#中的值类型应该很小,因此按值传递的效率很高,因此通常不需要"const引用"的概念来说明"我想通过引用传递这个以提高性能,但实际上不改变变量"。

1)我想把它模板化,这样它就可以接受任何可以乘以浮点数的类型

不确定当前c#中泛型的实现是否可行。不能定义T where T : float。编译器会告诉你only class or interface could be specified as constraint .

2)我不确定是否应该使此静态. ...

我不会使一个类静态,因为你有一个静态方法在它。我看不出你定义的方法有什么问题。由于它不使用成员,所以将其设置为静态是有意义的(看起来像一个helper方法)。您也可以将其作为马修斯回答中建议的扩展方法。比如:

public static class Vector2Ext
{
    public static Vector3 BiLerp(
        this Vector2 _uv,
        Vector3 _00,
        Vector3 _01,
        Vector3 _10,
        Vector3 _11)
    {
        // your implementation
    }
}

这样您就可以将方法BiLerp作为Vector2上的方法调用。

Vector2 vector2 = ...;
vector2.BiLerp(_00, _01, _10, _11);

如果以这种方式设计它是有意义的,那么在这种情况下你可能会做出最好的判断。

3) c#的const在这种情况下是如何工作的?

有点模糊,不确定你的意思。MSDN在这里有帮助吗?

4)在c++中,我将通过引用传递参数。如果我正确地假设c#已经这样做了吗?ref关键字是另一个黑魔法工具吗?

这本身就是一个话题。如果使用ref关键字,则传递类型作为引用。如果VectorXD是不可变类型,这是有意义的。如果需要在调用端返回valuetype的值,则需要通过ref传递它们。看看你的代码,我解释它为你传递一些值,用它们来计算一个Vector3D,并返回。我不认为这里需要ref。但也许我又误解了你的问题。也许MSDN有助于理解ref的用法。

c#没有模板,因为它们在c++中是众所周知的。术语是generics,它们比c++代码中的模板更受约束。对于您所需要的,不可能从float类型继承,也不可能将泛型约束放入数字类型,因为floatValueType。c#(以及一般的。net)中的值类型不能通过类型继承来扩展。

建议您可以直接使用floatdouble。c#从所有其他数字类型(可能除了decimal)自动强制转换为floatdouble