2012-01-19 2 views
9

Предположим, у меня есть на структуру с помощью только одного поля:Должен ли я определять каждый оператор?

public struct Angle 
{ 
    public static readonly double RadiansPerDegree = Math.PI/180; 

    private readonly double _degrees; 

    public Angle(double degrees) 
    { 
     _degrees = degrees; 
    } 

    public double Degrees 
    { 
     get { return _degrees; } 
    } 

    public double Radians 
    { 
     get { return _degrees * RadiansPerDegree; } 
    } 

    public static Angle FromDegrees(double value) 
    { 
     return new Angle(value); 
    } 

    public static Angle FromRadians(double value) 
    { 
     return new Angle(value/RadiansPerDegree); 
    } 
} 

Это прекрасно работает, пока я не хочу делать вещи, как это:

var alpha = Angle.FromDegrees(90); 
var beta = Angle.FromDegrees(100); 
var inequality = alpha > beta; 
var sum = alpha + beta; 
var negation = -alpha; 
//etc. 

Итак, я реализовал IEquatable<in T> и IComparable<in T>, но которые до сих пор не разрешалось ни одному оператору (даже не ==, <, >= и т. д.).

Итак, я начал предоставлять операционные перегрузки.

Например:

public static Angle operator +(Angle a, Angle b) 
{ 
    return new Angle(a._degrees + b._degrees); 
} 

public static Angle operator -(Angle a) 
{ 
    return new Angle(-a._degrees); 
} 

public static bool operator >(Angle a, Angle b) 
{ 
    return a._degrees > b._degrees; 
} 

Это работало, однако, когда я смотрел на всех операторов я вполне может перегружать (+, -, !, ~, ++, --, true, false, +, -, *, /, %, &, |, ^, <<, >>, ==, !=, <, >, <=, >=), я начал чувствовать, что должен быть лучший способ. В конце концов, структура содержит только одно поле, и это поле является типом значения.

Есть ли способ разрешить всем операторам double одним выстрелом? Или мне действительно нужно набирать каждого оператора, которого я, возможно, захочу поддержать вручную?

(Даже если у меня было два или три поля, я все же хотел бы иметь возможность добавлять операторы в одной партии ...)

+3

Вы могли бы добавить неявных приведений (и, возможно, от) тип 'double', чтобы сделать это. Хотя, что-то в моей голове говорит мне, что это может быть не очень хорошая идея и может привести к двусмысленности. –

+1

Если вы действительно делаете это только для преобразования степени и радиана, почему бы просто не создать статический класс MathHelper, который реализует эту функцию и просто использовать double вместо создания класса, который повторно изобретает другой класс с другим именем? –

+0

@Jeff Mercado, я думаю, что неявный бросок может быть именно тем, что я ищу, на самом деле. Не могли бы вы перевести свой комментарий в ответ? Кроме того, если на самом деле есть недостаток, я бы очень признателен, если бы вы могли немного расшириться. Благодарю. – devuxer

ответ

12

Точка перегрузки операторов, чтобы определить, как добавить манипулировать объекты пользовательского типа с использованием этих операторов, поэтому, если ваше второе поле было строковым массивом, как бы вы ожидали, что оператор ++ будет реализован автоматически? Нет разумного ответа, тем более, что мы не знаем контекста объекта или его использования, поэтому ответ да, вам придется перегружать операторов самостоятельно.

Для записи, если вам действительно нужно только одно поле, и это просто двойное, тогда не используйте структуру в первую очередь, если вам не нужно перегружать операторов для выполнения каких-либо других действий, чем они делают default - это явный случай чрезмерной инженерии!

+0

Пример «Угол» - это упрощение, но моя цель - четко указать, что такое единицы, и инкапсулировать необходимое преобразование единиц в один тип. Итак, если у меня есть «Угол», нет никакой двусмысленности в отношении единиц, я просто хватаюсь за то, что мне нужно. То, что я получал с моим вопросом, было то, что я хотел бы, чтобы кто-то мог сказать компилятору, что я хочу, чтобы структура вела себя так, как будто это основное поле для всех операций. Предложение @Jeff Mercado использовать неявные броски * кажется * для этого, но он, похоже, обеспокоен тем, что могут быть непреднамеренные последствия. – devuxer

+0

Как только типы являются чем-то более сложным, чем примитивные, вы можете увидеть, как система не сможет генерировать значимые операции для данных. По крайней мере, вы знаете, что делаете! Я бы предложил создать макрос в среде IDE, такой как Vim, для генерации всех операторов для ваших структур, если это то, что вы будете делать более одного раза. –

+0

Я думаю, что во всех моих случаях, которые я предвижу для этого конкретного проекта, я могу неявно преобразовать весь тип в один тип родного значения для выполнения операций, но если я сталкиваюсь с чем-то более сложным, идея макроса для генерации перегрузки операторов звучат хорошо. – devuxer

0

Да, вы должны определить каждый оператор, который хотите использовать. Компилятор не знает, что вам нужно от каждого оператора, кроме операторов, которые являются негативами друг друга (и даже это может быть не обязательно очевидным: что, если вы хотите имитировать стандартное поведение SQL-null, где оба: == и != вернет false по сравнению с null?).

0

В большинстве случаев я согласен с LaceySnr: он не работает ни для каких операторов, которые возвращают ваш новый объект (например, +, * ect.). Для компараторов это могло бы работать (так как в нем может быть аннотация, в которой говорится, что «использовать возвращаемое значение этого метода для этого объекта при использовании во всех операциях компаратора»), но я ничего не знаю об этом.

Я не уверен, что ограничения аннотаций находятся на C#, но может быть возможно создать тот, который делает это (для операторов, которые возвращают bool), но если вы не планируете его очень использовать, я сомневаюсь это будет стоить вашего времени.

Сказав это, если у вас должен был быть объект, который в конструкторе принимал ровно один аргумент, и этот аргумент был возвращаемым значением метода, это также можно сделать для этого.

Конечно, чтобы сделать все это потребует некоторых довольно экстремальный класс-мастерить, который я на самом деле не в ситуации, чтобы дать советы по ...

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