2014-09-18 3 views
3

Пусть два класса со следующей неявной и явной шаблон оператора:О разрешении перегрузки оператора

class Foo 
{ 
    public static implicit operator decimal (Foo foo) 
    { 
     throw new NotImplementedException(); 
    } 

    public static implicit operator Foo (decimal value) 
    { 
     throw new NotImplementedException(); 
    } 

    public static Foo operator +(Foo left, Foo right) 
    { 
     throw new NotImplementedException(); 
    } 
} 

class Bar 
{ 
    public static explicit operator decimal (Bar bar) 
    { 
     throw new NotImplementedException(); 
    } 

    public static explicit operator Foo(Bar bar) 
    { 
     throw new NotImplementedException(); 
    } 
} 

Теперь рассмотрим следующий код:

var foo = new Foo(); 
var bar = new Bar(); 
var resultFooAddBar = foo + (decimal)bar; 

неявно типизированным resutlFooAddBar решает Foo и оператор добавления разрешается до Foo Foo.operator +. Почему этот код не дает неоднозначной ошибки? Оператор мог бы в равной степени разрешить decimal decimal.operator +. Это потому, что пользовательские операторы: всегда считается лучшим вариантом? Тем не менее, выбор кажется немного странным, учитывая, что Bar имеет явное приведение Foo, который не был использован, который будет явно определить какой оператор программист хотел бы использовать:

var resultFooAddBar = foo + (Foo)bar; // OK, я явно говорю Я хочу Foo Foo.operator +

Если вместо decimal мы используем третий класс Tango, определяющие Tango Tango.operator + (Tango, Tango) и тот же скрытые и явные модели оператора тогда Неоднозначная ошибка вызова, брошенный компилятор.

Почему это различие между определенными пользователем операторами и не определенными пользователем операторами?

UPDATE: Я создал отдельный узел, включающий в следующий класс, чтобы опробовать exlanation Servy в:

namespace ExternalAssembly 
{ 
    public class Tango 
    { 
     public static Tango operator +(Tango left, Tango right) 
     { 
      throw new NotImplementedException(); 
     } 
    } 
} 

, а затем изменили decimal к Tango в Foo и Bar и добавив необходимую ссылку на ExternalAssembly длл. В этом случае я все еще получаю «+» оператор неоднозначен в операндах «ConsoleApplication.Foo» и «ExternalAssembly.Tango». Почему бы не компилятор, в этом случае, выбрать ту же самую перегрузку Foo Foo.operator +, что и в моем исходном вопросе с decimal?

+0

@Servy 'decimal' +' decimal'. Существует неявное преобразование из 'Foo' в' decimal', но вместо этого компилятор выбирает неявное преобразование из 'decimal' в' Foo'. См. Последний абзац (только что измененный). – InBetween

ответ

1

Алгоритмы разрешения перегрузки имеют ряд показателей «блеска», с помощью которых они определяют, какая из нескольких применимых перегрузок метода/оператора должна использоваться. Только если ни одна из этих метрик не имеет окончательно «лучшей» перегрузки, есть ошибка двусмысленности.

Одним из показателей для более высокой степени является «близость» определения перегрузки, о которой идет речь, к сайту вызова. Определение в том же классе «ближе», чем определение вне его, определение во внешнем классе ближе, чем определения вне этого родительского типа, определения в том же пространстве имен ближе, чем определения во внешних пространствах имен и т. Д. Ваше определение «ближе», чем десятичный оператор +. (См. this article для получения дополнительной информации по этому вопросу.)

+0

Хорошо, что я более или менее ожидал увидеть, как ведет себя операторское разрешение. Но все же мне кажется, что, как и во всех проектах, есть компромиссы, чтобы не сделать его чрезмерно сложным. В этом случае наличие явного приведения, которое вы не хотите использовать, должно быть своего рода флагом для компилятора, чтобы понять, что, возможно, он не выбирает «лучший» оператор.Во всяком случае, в моей стране говорится: «Совершенство - враг добра *, поэтому способ, которым он работает, является, вероятно, лучшим. – InBetween

+0

Если я создаю слово 'Tango' в отдельной сборке и с другим пространством имен, я все равно получаю двусмысленный вызов. Почему в этом случае это будет отличаться от десятичного? – InBetween

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