Water Cooler v2
Water Cooler v2

Reputation: 33870

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?

Upvotes: 15

Views: 3648

Answers (5)

Eli Arbel
Eli Arbel

Reputation: 22749

Conversion 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);

Upvotes: 13

Sriram Sakthivel
Sriram Sakthivel

Reputation: 73492

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

Upvotes: 5

SdSdsdsd
SdSdsdsd

Reputation: 123

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.

Upvotes: 1

p.s.w.g
p.s.w.g

Reputation: 149030

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

Upvotes: 6

Henrik
Henrik

Reputation: 23324

Use Select:

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

Upvotes: 2

Related Questions