扩展方法(C#)中的值不会更改

时间:2013-03-28 06:16:02

标签: c# vector extension-methods

我正在为CAD系统编写插件。不幸的是,这个系统的API很糟糕。所以,我写了Vector3d类的扩展。这是(C#代码):

/// <summary>
///     Normalizes the vector by dividing it’s all coordinates with the vector's norm.
/// </summary>
/// <param name="v">
///     This vector.
/// </param>
/// <returns>
///     Returns vector's norm.
/// </returns>
public static double Normalize(this Vector3d v)
{
    var norm = v.Norm();
    var invNorm = 1.0 / norm;

    v.X *= invNorm;
    v.Y *= invNorm;
    v.Z *= invNorm;

    return norm;
}

但是我有一个问题:当这个方法执行时,矢量的坐标会改变。但是,当方法执行时,矢量坐标具有原始值。

我对其他扩展方法没有任何问题。

2 个答案:

答案 0 :(得分:1)

在假设Vector3d是结构的情况下工作:

参数(无论是否为扩展方法的'this'参数)都按值传递。您使用的参数实际上是原始vector3的副本。

建议将其更改为:

public static double NormalizeVector3d(ref Vector3d v);

或者:

public static Vector3d GetNormalizedVector3d(Vector3d v, out double norm);

无论哪种方式,都无法使用扩展方法进行呼叫。

答案 1 :(得分:1)

正如leppie所提到的,Vector3d可能是struct,而不是一个类。

这意味着它是value type,并将其作为参数传递给您的扩展方法,可以有效地创建该对象的副本。您的扩展方法会更改副本,然后在退出方法时将其丢弃。

我找不到这个.NET API的良好API参考,但这也可能是您认为API“不好”的原因。修改Vector3d的方法将返回原始向量的副本,而不是对对象本身进行操作。或者,他们可以使用参考参数,这也是你可以做的:

public static double Normalize(ref Vector3d v)

假设它是一个结构体(如果没有更多信息我想不到另一种解释),API的创建者应该使结构不可变。可变结构是这些问题的处方。

就个人而言,我可能会写这样的方法:

public static Vector3d Normalize(this Vector3d v, out double norm)
{
    norm = v.Norm();
    var invNorm = 1.0 / norm;

    // Using a constructor with x, y, z parameters would be preferable,
    // if it exists.
    v.X *= invNorm;
    v.Y *= invNorm;
    v.Z *= invNorm;

    return v;
}

ref选项不同,它可以作为扩展方法编写。