5

寻求有关 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. 我想让它成为通用的,以便它接受任何可以乘以浮点数的类型
  2. 我不确定是否应该将其设为静态。我假设因为它不使用任何成员变量,所以是的。如果存储它的类也是静态的,那么该类将仅用于统一(Matrix2x2)等省略的数学助手。
  3. C# const 在这种情况下如何工作?
  4. 在 C++ 中,我将通过引用传递参数。II 正确假设 C# 已经在这样做了吗?并且 ref 关键字是其他一些黑暗魔法工具?

如果有任何其他建议,请随时提出。我现在只在 C# 中工作了 6 周,可以使用任何建议。

4

4 回答 4

6
  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++ 术语中的指针)来加速它。

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

于 2013-03-23T11:25:27.727 回答
4

我想让它成为通用的,以便它接受任何可以乘以浮点数的类型

不幸的是,C# 的泛型类型系统不支持这种约束。这是 C# 团队考虑的一个相当频繁请求的功能,但它需要在底层 CLR 类型系统中进行大量工作。将来有可能会实施,但如果我是你,我不会屏住呼吸等待那一天。

我不确定是否应该将其设为静态。我假设因为它不使用任何成员变量,所以是的。

是的,让它成为静态的。

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

是的。

C# const 在这种情况下如何工作?

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

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

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

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

不,值类型是按值传递的。

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

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

于 2013-03-23T16:51:11.267 回答
2

1)我想对它进行模板化,以便它接受任何可以乘以浮点数的类型

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

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

我不会将类设为静态,因为其中有 1 个静态方法。我认为您定义的方法没有问题。因为它不使用成员所以使它成为静态是有意义的(看起来像一个辅助方法)。您也可以按照 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++ 中,我将通过引用传递参数。II 正确假设 C# 已经在这样做了吗?并且 ref 关键字是其他一些黑暗魔法工具?

这本身就是一个话题。如果使用ref关键字,则将类型作为引用传递。VectorXD如果是不可变类型,这是有道理的。如果您需要在调用方返回 valuetype 的值,您希望通过 ref 传递它们。查看您的代码,我在您传递一些值时对其进行解释,使用它们来计算 aVector3D并返回它。我不认为ref这里有必要。但也许我再次误解了你的问题。也许MSDN有助于理解ref.

于 2013-03-23T11:25:17.820 回答
1

C# 没有模板,因为它们在 C++ 中是众所周知的。术语是generics,它们比 C++ 代码中的模板更受限制。对于您的要求,不可能从float类型继承,也不可能对数字类型施加泛型约束,float因为ValueType. C#(和一般的 .NET)中的值类型不能通过类型继承来扩展。

作为建议,您可以使用floatdouble直接使用。C# 对所有其他数字类型(可能除外)执行float自动double转换decimal

于 2013-03-23T11:26:11.533 回答