Aqui está um exemplo mínimo reproduzível:
// Implicit and explicit conversions are overloadable operators:
Note note = new Note (9);
Console.WriteLine(note);
Note n = (Note)554.37;
double x = n;
Console.WriteLine(n);
Console.WriteLine(x);
public struct Note
{
int value;
public int SemitonesFromA { get { return value; } }
public Note (int semitonesFromA) { value = semitonesFromA; }
// Convert to hertz
public static implicit operator double (Note x) => 440 * Math.Pow (2, (double)x.value / 12);
// Convert from hertz (accurate to the nearest semitone)
public static explicit operator Note (double x) =>
new Note ((int)(0.5 + 12 * (Math.Log (x / 440) / Math.Log (2))));
public override string ToString() => $"{SemitonesFromA} semitones from A";
}
Eu esperaria
9 semitones from A
4 semitones from A
554.3652619537442
Mas eu entendo
739.9888454232688
554.3652619537442
554.3652619537442
Acho que é porque na "ordem de prioridades" de Console.WriteLine, implícitar a conversão para double tem mais prioridade do que chamar .ToString() no tipo Object. Como isso funciona? Como posso saber, olhando a documentação ( https://learn.microsoft.com/en-us/dotnet/api/system.console.writeline?view=net-8.0#overloads ), qual sobrecarga está selecionada?
Ele apenas seleciona a correspondência "mais próxima".
Sua expectativa é
Console.Writeline
invocarToString
implicitamente.Mas não irá, se tiver sobrecarga correta para o tipo. E
Console.WriteLine
infere sobrecarga correta, comoNote
é implicitamente convertível paradouble
, que então correspondeConsole.WriteLine(double)
exatamente à sobrecarga e não prossegue para chamar sobrecarga geral comobject?
um tipo de parâmetro, que apenas invocaToString
o método.Você pode passar o mouse sobre sua chamada
Console.WriteLine
e ver qual sobrecarga será usada:E se você alterar seu operador implícito para um explícito, você obterá o que espera: