Some cast problem and something about generic

T

Tony

Hello!

Below I have a complete working program.with some simple classes one of
these is a generic class.

The question is about this method GetCows() {...} which is a member in the
generic class.
I have two questions about this method.
Question number 1:
If I use "(Cow)animal" insted of "animal as Cow" I get the following compile
error
Error 1 Cannot convert type 'T' to 'ConsoleApplication15.Cow'
C:\tony\ConsoleApplication15\ConsoleApplication15\Program.cs 115 38
ConsoleApplication15
Why ?
But If I change the foreach clause to foreach (Animal animal in animals)
{...}
I can use this cast "(Cow)animal"
Normally I can use which ever of these cast principle (Cow)animal or animal
as Cow
but not here because I'm forced to use the animal as Cow


Question number 2:
I have the generic class Farm containing Animal(i.e is a Animal)
Why is it not possible to have this foreach in GetRows()
like this
foreach (Cow animal in animals)
{...}
If I do I get the following compile error
Error 1 Cannot convert type 'T' to 'ConsoleApplication15.Cow'
C:\tony\ConsoleApplication15\ConsoleApplication15\Program.cs 114 13
ConsoleApplication15
Why ?
I can have foreach (Animal animal in animals)


public Farm<Cow> GetCows()
{
Farm<Cow> cowFarm = new Farm<Cow>();
foreach (T animal in animals)
if (animal is Cow)
cowFarm.animals.Add(animal as Cow);

return cowFarm;
}




using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;

namespace ConsoleApplication15
{
class Program
{
static void Main(string[] args)
{
Farm<Animal> farm = new Farm<Animal>();
farm.Animal.Add(new Cow("Jack"));
farm.Animal.Add(new Chicken("Vera"));
farm.Animal.Add(new Chicken("Sally"));
farm.Animal.Add(new SuperCow("Kevin"));

farm.MakeNoises();

Farm<Cow> dairyFarm = farm.GetCows();
dairyFarm.FeedTheAnimals();

foreach (Cow cow in dairyFarm)
if (cow is SuperCow)
((SuperCow)cow).Fly();

Farm<Animal> newFarm = farm + dairyFarm;
Console.ReadKey();
}
}

public abstract class Animal
{
string name;
public Animal(string name)
{ this.name = name; }

public string Name
{ get { return name; } }

public abstract void MakeANoise();
public abstract void Feed();
}

public class Chicken : Animal
{
public Chicken(string name) : base(name) {}

public override void MakeANoise()
{ Console.WriteLine("{0} says 'cluck!'", Name); }

public override void Feed()
{ Console.WriteLine("{0} has been feed(Chicken)", Name); }
}

public class Cow : Animal
{
public Cow(string name) : base(name) {}

public override void MakeANoise()
{ Console.WriteLine("{0} says 'moo!'", Name); }

public override void Feed()
{ Console.WriteLine("{0} has been feed(Cow)", Name); }
}

public class SuperCow : Cow
{
public SuperCow(string name) : base(name) {}

public void Fly()
{ Console.WriteLine("{0} is flying!", Name); }

public override void MakeANoise()
{ Console.WriteLine("{0} says 'here I come to save the day!'",
Name); }

public override void Feed()
{ Console.WriteLine("{0} has been feed(SuperCow)", Name); }
}

public class Farm<T> : IEnumerable<T>
where T : Animal
{
private List<T> animals = new List<T>();

public List<T> Animal
{ get { return animals; } }

public IEnumerator<T> GetEnumerator()
{ return animals.GetEnumerator(); }

IEnumerator IEnumerable.GetEnumerator()
{ return animals.GetEnumerator(); }


public void MakeNoises()
{
foreach (T animal in animals)
animal.MakeANoise();
}

public void FeedTheAnimals()
{
foreach (T animal in animals)
animal.Feed();
}

public Farm<Cow> GetCows()
{
Farm<Cow> cowFarm = new Farm<Cow>();
foreach (T animal in animals)
if (animal is Cow)
cowFarm.animals.Add(animal as Cow);
return cowFarm;
}

public static Farm<T> operator +(Farm<T> farm1, Farm<T> farm2)
{
Farm<T> result = new Farm<T>();
foreach (T animal in farm1)
result.Animal.Add(animal);

foreach (T animal in farm2)
if (!result.Animal.Contains(animal))
result.Animal.Add(animal);
return result;
}

public static implicit operator Farm<Animal>(Farm<T> farm)
{
Farm<Animal> result = new Farm<Animal>();

foreach(T animal in farm)
result.Animal.Add(animal);
return result;
}
}
}

//Tony
 
J

Jon Skeet [C# MVP]

Hello!

Below I have a complete working program.with some simple classes one of
these is a generic class.

The question is about this method GetCows() {...} which is a member in the
generic class.
I have two questions about this method.
Question number 1:
If I use "(Cow)animal" insted of "animal as Cow" I get the following compile
error
Error 1 Cannot convert type 'T' to 'ConsoleApplication15.Cow'

I don't know. Oddly enough, you *can* do:

(Cow)(Animal)animal;

There's an implicit conversion from T to animal, so I would have
expected it to work.

I'll delve into the spec to see what's going on. It could just be a
compiler bug.

Jon
 
T

Tony

Hello!

What about question number 2 in the previous mail?

//Tony


"Jon Skeet [C# MVP]" <[email protected]> skrev i meddelandet
Hello!

Below I have a complete working program.with some simple classes one of
these is a generic class.

The question is about this method GetCows() {...} which is a member in the
generic class.
I have two questions about this method.
Question number 1:
If I use "(Cow)animal" insted of "animal as Cow" I get the following compile
error
Error 1 Cannot convert type 'T' to 'ConsoleApplication15.Cow'

I don't know. Oddly enough, you *can* do:

(Cow)(Animal)animal;

There's an implicit conversion from T to animal, so I would have
expected it to work.

I'll delve into the spec to see what's going on. It could just be a
compiler bug.

Jon
 
J

Jon Skeet [C# MVP]

What about question number 2 in the previous mail?

It's basically the same thing, I expect. Think of foreach as
implicitly inserting a cast - it's translating (ignoring disposal etc)
the code into:

IEnumerator<T> iterator = animals.GetEnumerator();
while (iterator.HasNext)
{
Cow cow = (Cow) iterator.Current;
// Your code here
}

The cast is failing in the same was as it did within the loop.

Just my current theory, anyway...

Jon
 
B

Ben Voigt [C++ MVP]

I don't know. Oddly enough, you *can* do:
(Cow)(Animal)animal;

There's an implicit conversion from T to animal, so I would have
expected it to work.

I'll delve into the spec to see what's going on. It could just be a
compiler bug.

I think it's because a cast can be either a runtime type check or an
op_Explicit call. It's the runtime type check when casting to a direct
ancestor or descendant in the inheritance tree. But Cow and T are both
descendants of Animal, and it would be legal, for any given T more loosely
related to Cow, to define an op_Explicit returning Cow. So the compiler
interprets the cast as the op_Explicit call, searches the constraints, finds
none such defined, and fails.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top