IEnumerable.即使定义了显式强制转换运算符,强制转换也不起作用

本文关键字:转换 运算符 不起作用 定义 IEnumerable | 更新日期: 2023-09-27 18:32:33

我有一个从类型 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使用我的投射运算符来尝试转换?

IEnumerable<T>.即使定义了显式强制转换运算符,强制转换也不起作用

转换运算符是在代码中使用强制转换时编译器调用的静态方法。它们不能动态使用。 Enumerable.Cast执行两个不受约束的泛型类型的运行时强制转换,因此它在编译时无法知道要使用哪个强制转换运算符。要做你想做的事,你可以使用 Select

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

linq Cast 方法本质上是一个盒子和取消一个盒子。它不知道 C# 中定义的隐式或显式强制转换运算符,编译器会处理这些运算符的标准方法调用。

你必须做这样的事情:

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

由于所有其他答案指向类型在编译时都未知Cast因为该方法不是generic。它包含object类型,并对T进行显式转换。此操作失败,因为您没有从 objectFoo 的转换运算符。这也是不可能的。

下面是使用动态的解决方法,其中转换将在运行时完成。

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

使用 Select

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

您的代码实际上并没有编译。我假设"酒吧"类中也有一个属性"Gar"?

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>

在 C# 的协方差(和逆变)概念中,"可转换"意味着可通过隐式引用转换进行转换,例如 A 子类化 B 或实现 B 的 A。

你必须用接口来做到这一点。