Добрый вечер!
Почему не компилируется неявная пользовательская конверсия в контексте кортежей? Какой пункт спецификации это описывает?
Если на то есть уважительные причины, то почему тогда компилируются другие пользовательские конверсии?
internal readonly struct Pair
{
public Pair(string name, string type)
{
Name = name;
Type = type;
}
internal string Name { get; }
internal string Type { get; }
public override string ToString() => $"{Name}: {Type}";
public static implicit operator Pair((string, int) t) => new Pair(t.Item1, "int");
public static implicit operator Pair((string, uint) t) => new Pair(t.Item1, "uint");
}
internal static class Program
{
private static void Render(Pair pair)
{
System.Console.WriteLine(pair);
}
private static void Main()
{
const uint u = 23;
Render(("u", u)); // u: uint
const int m = -1;
Render(("-", m)); // -: int
const int i = 42;
Render(("i", i)); // Error CS0457
var t = ("t", i);
Render(t); // t: int
}
}
Текст ошибки:
Ambiguous user defined conversions 'Pair.implicit operator Pair((string, int))' and 'Pair.implicit operator Pair((string, uint))' when converting from '(string, int i)' to 'Pair'
Смотреть тут:
https://stackoverflow.com/questions/9017363/ambiguous-method-overloading
https://stackoverflow.com/questions/9008637/why-does-this-implicit-conversion-from-int-to-uint-work/9008765#9008765
В общем фишка нужна, чтобы не надо было писать тип явно для значений умещающихся в byte, short:
const int a = 1;
byte b = a; // OK
Integer constant conversions are treated as very special by the C# language; here's section 6.1.9 of the specification:
A constant expression of type int can be converted to type sbyte, byte, short, ushort, uint, or ulong, provided the value of the constant-expression is within the range of the destination type. A constant expression of type long can be converted to type ulong, provided the value of the constant expression is not negative.
Здравствуйте, _NN_, Вы писали:
_NN>В общем фишка нужна, чтобы не надо было писать тип явно для значений умещающихся в byte, short
Это не объясняет двух вещей.
1) В последнем тесте вывод типа и выбор перегрузки выполнился корректно, как ожидается:
var t = ("t", i);
Render(t); // t: int
При этом тот же тип выводится ровно так же при прямой подстановке в вызов, только в случае этой прямой подстановки почему-то возникает неоднозначность.
const int i = 42;
Render(("i", i)); // Error CS0457
2) Аналогичный пример без кортежей успешно компилируется, хотя к нему применимы те же рассуждения про конверсии из int:
internal readonly struct Pair
{
public Pair(string name, string type)
{
Name = name;
Type = type;
}
internal string Name { get; }
internal string Type { get; }
public override string ToString() => $"{Name}: {Type}";
public static implicit operator Pair(int value) => new Pair(value.ToString(), "int");
public static implicit operator Pair(uint value) => new Pair(value.ToString(), "uint");
}
internal static class Program
{
private static void Render(Pair pair)
{
System.Console.WriteLine(pair);
}
private static void Main()
{
const uint u = 23;
Render(u); // 23: uint
Render(23u); // 23: uint
const int m = -1;
Render(m); // -1: int
Render(-1); // -1: int
const int i = 42;
Render(i); // 42: int
Render(42); // 42: int
}
}
Здравствуйте, Qbit86, Вы писали:
Думаю тут нужен nikov или Эрик Липперт.
Не удивлюсь если просто в компиляторе забыли реализовать это для кортежей.