Неявные преобразования разрешены для цели вызовов методов расширения, но они ограничены.Из раздела 7.5.6.2 стандарта ECMA C # 5:
Метод расширения Ci.Mj подходит, если:
- ...
- Неявное преобразование идентификатора, ссылки или бокса существует из expr в тип первого параметра Mj .
В вашем случае это не преобразование идентификатора, ссылки или бокса, поэтому этот метод неприемлем.
Мы используем приемлемые мутации почти каждый раз, когда используем LINQ.Например:
List<string> names = new List<string> { "a", "b" };
IEnumerable<string> query = names.Select(x => x.ToUpper());
Здесь целью метода является IEnumerable<T>
, но тип аргумента - List<string>
.T
определяется как string
, но все еще требуется преобразование из List<string>
в IEnumerable<string>
.Это разрешено, хотя, поскольку это преобразование ссылок .
Я могу понять, почему правило существует, по крайней мере, для ссылочных типов.Предположим, у нас был изменяемый ссылочный тип X
с неявным преобразованием в другой изменяемый ссылочный тип Y
.Метод расширения, нацеленный на Y
, который мутировал его, был бы очень запутанным, потому что он, вероятно, не изменил бы исходный X
.Методы расширения предназначены для того, чтобы «чувствовать», что они действуют на исходное значение, и это не тот случай, когда допустимы преобразования, отличные от перечисленных.
Даже преобразования в бокс кажутся мне немного сомнительными.Вот пример использования изменяемой структуры, которая реализует интерфейс:
using System;
public interface IMutable
{
void Mutate();
}
public static class MutationExtensions
{
public static void CallMutate(this IMutable target)
{
target.Mutate();
}
}
public struct MutableStruct : IMutable
{
public int value;
public void Mutate()
{
value++;
}
}
class Program
{
static void Main()
{
MutableStruct x = new MutableStruct();
Console.WriteLine(x.value); // 0
x.Mutate();
Console.WriteLine(x.value); // 1
x.CallMutate();
Console.WriteLine(x.value); // 1
}
}
Этот последний результат (1, а не 2) состоит в том, что значение было помечено как IMutable
, и только поле было изменено- не переменная x
.
Я подозреваю, что подобные угловые случаи считались «приемлемо неприятными», имея в виду преимущество возможности писать методы расширения для других интерфейсов, которые могут реализовывать типы значений, такие как IFormattable
.(По общему признанию универсальный метод с ограничением на параметр типа, вероятно, был бы лучшей идеей там).