IEnumerable <T>.Cast не будет работать, даже если определен явный оператор литья?

У меня есть явное преобразование, определенное из типа Bar, чтобы напечатать Foo.

public class Bar
{
  public static explicit operator Foo(Bar bar)
  {
    return new Foo(bar.Gar);
  }
}

public class Foo
{
  public string Gar { get; set; }

  public Foo() { }

  public Foo(string gar) { Gar = gar; }
}

Однако, когда я это делаю:

using System.Linq;

...

var manyFoos = manyBars.Cast<Foo>();

Он выдает исключение, говорящее, что он не может использовать.

Как мне сказать Cast использовать мой оператор трансляции, чтобы попробовать преобразовать?

Ответ 1

Операторы роли - это статические методы, которые вызывает компилятор при использовании бросков в коде. Они не могут использоваться динамически. Enumerable.Cast выполняет время выполнения из двух неограниченных общих типов, поэтому во время компиляции, которые используют операторы-листы, он не может знать. Чтобы сделать то, что вы хотите, вы можете использовать Select:

manyFoos.Select(foo => (Bar)foo);

Ответ 2

Метод linq Cast по существу делает поле и unbox. Он не знает ни о неявных, ни явных операторах литья, определенных в С#, которые компилятор рассматривает стандартные вызовы методов.

Вам нужно будет сделать что-то вроде этого:

var manyFoos = manyBars.Select(bar => (Foo)bar);

Ответ 3

Как и во всех других ответах, тиковый тип не известен во время компиляции, так как Cast метод не generic. Он содержит тип object и делает явное приведение к T. это не работает, потому что у вас нет оператора преобразования от object до Foo. И это также невозможно.

Вот работа с использованием динамики, в которой литье будет выполняться во время выполнения.

public static class DynamicEnumerable
{
    public static IEnumerable<T> DynamicCast<T>(this IEnumerable source)
    {
        foreach (dynamic current in source)
        {
            yield return (T)(current);
        }
    }
}

Затем используйте его как

 var result = bars.DynamicCast<Foo>();//this works

Ответ 4

Используйте Select:

var manyFoos = manyBars.Select(bar => (Foo)bar);

Ответ 5

Ваш код фактически не компилируется. Я предполагаю, что в классе "Бар" есть свойство "Гар"?

public class Bar
    {
        public string Gar { get; set; }

        public static explicit operator Foo(Bar bar)
        {
            return new Foo(bar.Gar);
        }
    }

    public class Foo
    {
        public string Gar { get; set; }

        public Foo() { }

        public Foo(string gar) { Gar = gar; }
    }

static void Main(string[] args)
        {

            List<Bar> bars = new List<Bar>();
            for (int i = 0; i < 10; i++)
                bars.Add(new Bar() { Gar = i.ToString() });

            var result = bars.Cast<Foo>();
        }

+

Я обманываю вас, чтобы прочитать о ковариации.

Предполагая, что A можно сместить в B, X ковариантно, если X<A> можно преобразовать в X<B>.

С понятием С# ковариации (и контравариантности) термин "конвертируемый" означает конвертируемое через неявное ссылочное преобразование, такое как A-подкласс B или реализация B. B. Числовые преобразования, преобразования бокса и пользовательские преобразования не включены.

Вы должны сделать это с помощью интерфейсов.