2013-03-28 3 views
0

Я пишу плагин для CAD-системы. К сожалению, эта система имеет плохой API. Итак, я написал расширение для класса Vector3d. Здесь (C# код):Значения не меняются в методе расширения (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; 
} 

Но у меня есть проблема: когда этот метод выполняет то координаты вектора в изменении. Но, когда метод был выполнен, векторные координаты имеют исходные значения.

У меня нет проблем с другими методами расширения.

+6

Позвольте мне угадать, 'Vector3d' является структурой. – leppie

ответ

1

Как упоминалось в leppie, Vector3d, вероятно, является struct, а не классом.

Это означает, что это value type, и передача его в качестве параметра вашего метода расширения эффективно создает копию объекта. Ваш метод расширения изменяет копию, которая затем отбрасывается при выходе из метода.

Я не могу найти хорошую ссылку API для этого .NET 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, он может быть записан как метод расширения.

+0

+1. Это может быть также свойство read only для ссылочного типа, возвращающее копию внутреннего поля, но более вероятно, что это тип значения (было бы лучше, если бы это был неизменный тип - такой код мог бы вызвать более очевидные ошибки). –

+0

На 'ref' - во многих случаях это было бы не полезно (т. Е. Свойство со значением типа всегда возвращает копию ...). –

1

Работа в предположении, что Vector3D является структурой:

Параметр (независимо от того, чтобы быть «это» параметр метода расширения или нет) передается по значению. Параметр, который вы используете, на самом деле является копией исходного вектора3.

Предлагайте изменить его на:

public static double NormalizeVector3d(ref Vector3d v); 

Или:

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

В любом случае, это не возможно, чтобы сделать вызов, используя метод расширения.

Смежные вопросы