简体   繁体   中英

IEnumerable<T>.Cast won't work even if an explicit cast operator is defined?

I have an explicit conversion defined from type Bar to type 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; }
}

However, when I do:

using System.Linq;

...

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

It throws an exception saying it can't cast.

How do I tell Cast to use my cast operator to try the conversion?

Cast operators are static methods that the compiler calls when you use casts in code. They cannot be used dynamically. Enumerable.Cast does a runtime cast of two unconstrained generic types, so it cannot know during compile time which cast operators to use. To do what you want, you can use Select :

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

The linq Cast method essentially does a box and unbox. It is not aware of either implicit or explicit cast operators defined in C#, which the compiler treats standard method calls.

You'd have to do something like this:

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

As all other answers pointed type is not known in compile time since Cast method is not generic . It holds type of object and makes a explicit cast to T . this fails because you don't have conversion operator from object to Foo . And that is not possible also.

Here is a work around using dynamics in which cast will be done in runtime.

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

Then use it like

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

使用Select

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

Your code doesn't actually compile. I assume that there is a property "Gar" in the "Bar" class as well?

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>();
        }

+

I encaurage you to read about covariance.

Assuming A is convertible to B, X is covariant if X<A> is convertible to X<B> .

With C#'s notion of covariance (and contravariance), “convertible” means convertible via an implicit reference conversion— such as A subclassing B, or A implementing B. Numeric conversions, boxing conversions, and custom conversions are not included.

You have to do that with interfaces.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM