C#通用函数

时间:2013-03-23 11:14:29

标签: c# generics math unity3d

在C#generics上寻求帮助。我在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. 我想将它设为通用的,以便它可以采用任何可以乘以浮点数
  2. 的类型
  3. 我不确定是否应该让这个静止。我假设因为它不使用任何成员变量然后是。如果存储的类也是静态的,那么该类将仅用于由unity(Matrix2x2)等省略的数学助手。
  4. C#const如何在这个实例中工作?
  5. 在C ++中,我会通过引用传递参数。我认为C#已经在做这个了吗?并且ref关键字是其他一些黑魔法工具?
  6. 如果还有其他建议,请随意。我现在只在C#工作了6个星期,可以使用任何建议。

4 个答案:

答案 0 :(得分:6)

  1. 虽然可以通过传入一个执行乘法的委托来实现这项工作,但速度会慢很多。我实际上认为你最好不要写多个重载。

  2. 是的,您应该将它放入静态类中。 (恕我直言!) 我打算建议你把它设为extension method,但经过反思,它有太多的参数使它变得有用。

  3. C#consts类似于C ++ consts,但普遍的共识是它们应该只是私有的(或可能是内部的)。

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

    public Vector3 BiLerp(
        ref Vector2 _uv, ref Vector3 _00, ref Vector3 _01,
        ref Vector3 _10, ref Vector3 _11)`
    
  5. 然而,这样做只有两个原因(对于结构):

    1. 因为您想要更改传入的原始值。

    2. 通过仅传递引用(即C ++术语中的指针)来加速它。

    3. 第一个不适用于你的代码,第二个对于这样的小结构似乎毫无意义(事实上,所有结构应该很小,因此它几乎不适用于设计良好的结构)

答案 1 :(得分:4)

  

我想使它成为通用的,以便它可以采用任何可以乘以浮点数

的类型

不幸的是,C#的泛型类型系统不支持这种约束。这是C#团队考虑过的一个经常被请求的功能,但它需要在底层CLR类型系统中进行大量工作。它有可能在未来实施,但如果我是你,我不会等到那一天。

  

我不确定我是否应该让它静止。我假设因为它不使用任何成员变量然后是。

是的,让它静止。

  

如果存储的类也是静态的,那么该类将仅用于数学助手。

  

C#const如何在这个实例中工作?

C#const与C ++ const不同;它简单得多。在C#中,const字段或本地只是编译时常数或字符串的名称,故事结束。 (好吧,你也可以有一个引用类型的const,但它必须是null,所以这并不是那么有趣。)没有这个“这里是一个引用但你不能调用任何改变它的方法”你看到的规则C#。

最佳做法是首先使所有值类型都不可变,因此C ++样式的const不是必需的。

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

  

在C ++中,我会通过引用传递参数。假设C#已经这样做,我是否正确?

没有。值类型按值传递。

  

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

ref关键字就像C ++引用一样:它使一个变量成为另一个的别名。通常只能在C#中使用 mutate 调用者提供的变量。正如我之前所说,C#没有“const引用”的C ++概念,但由于C#中的值类型应该很小,因此通过值传递是有效的,因此通常不需要“const”的概念引用“to say”我希望通过引用传递这个性能,但实际上并没有改变变量“。

答案 2 :(得分:2)

1)我想对它进行模板处理,以便它可以采用任何可以乘以浮点数的类型

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

2)我不确定是否应该将其设为静态。 ......存储的类也应该是静态的

我不会让一个类静态,因为你有一个静态方法。我没有看到您定义的方法存在问题。使它静态,因为它不使用成员是有道理的(看起来像一个辅助方法)。您也可以将其作为Matthews答案中建议的扩展方法。类似的东西:

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的使用情况。

答案 3 :(得分:1)

C#没有模板,因为它们在C ++中是已知的。术语是generics,它们比C ++代码中的模板更受限制。 根据您的需要,不可能继承float类型,也不可能将通用约束放入数字类型,因为floatValueType。 C#(和一般的.NET)中的值类型不能通过类型继承来扩展。

作为建议,您可以直接使用floatdouble。 C#从所有其他数字类型(可能除float之外)对doubledecimal执行自动投射。