4
namespace ConsoleApp3
{
    class Program
    {
        // Main method - entry point of program
        static void Main(string[] args)
        {
            var animals = new Stack<Animal>();
            ZooCleaner.Wash(animals);
        }
    }

    //Simple classes declared and inherited.
    public class Animal { }
    public class Bear : Animal{ }
    public class Camel : Animal { }

    public class Stack<T> //Basic stack implementation
    {
        int position;
        T[] data = new T[100];
        public void Push(T obj) => data[position++] = obj;
        public T Pop() => data[--position];
    }

    public class ZooCleaner
    {
        public static void Wash<T>(Stack<T> animals) where T:Animal
        {
            //Why I cannot do this? I have correctly stated that 'T' can 
            //be of type Animal or can derive Animal but this
            //still causes compilation error!

            animals.Push(new Animal()); //Error: Cannot convert from 'Animal' To Type T!!
            animals.Push(new Bear()); //Error: Cannot convert from 'Bear' To Type T!!
        }
    }
}

问题:

在 Wash() 方法中,我正确地将通用参数“T”设置为“动物”类型或可以从“动物”派生。那么为什么我不能进行推送操作来插入 Animal 或 Bear 的对象呢?

为什么会animals.Push(new Animal()); animals.Push(new Bear());导致编译错误?

4

2 回答 2

2

这是正常的,也是意料之中的。如果你有一个Stack<T> where T : Animal,那么你必须想象它T可能是这样的Giraffe。唯一允许您推动 a 的Stack<Giraffe>a或a的Giraffe东西(a , a等)。您不能推动 a或 an :它必须是 a(或更好)。GiraffeMasaiGiraffeNubianGiraffeBearAnimalGiraffe

在 的情况下T,这意味着您可以推动T- 也许是 a new T()(通过T : new()约束)。

如果您希望能够推送任何内容Animal:不要使用Stack<T> where T : Animal- 使用Stack<Animal>

于 2019-09-10T08:58:31.500 回答
-1

欢迎来到 C#。这是 C# 编译器的一个非常烦人的限制。您会期望这适用于任何其他语言,因为它在 OOP 范式中是有意义的。

OP 我希望您知道 C# 中已经有堆栈的实现。如果它与不接受继承类型有相同的问题,那么您可以使用包含此通用项的包装器。这很痛苦,但你选择了CS。

所以你必须做一个工作。这也不是一个有趣的解决方法。这里是:

> public class Stack<T>
  {
    public int position => data.Count - 1;
    IList<T> data = new List<T>();
    public void Push(T obj) => data.Add(obj);

    public T Pop()
    {
        var ret = data[position];
        data.RemoveAt(position);
        return ret;
    }

    public override string ToString()
    {
        return $"Num of elements: {data.Count}. {data}";
    }
  }

> public class Animal { }
  public class Bear : Animal{ }
  public class Camel : Animal { }

> var sta = new Stack<Animal>();
  sta.Push(new Animal());
  sta.Push(new Bear());
  sta.Push(new Camel());

> sta
[Num of elements: 3. System.Collections.Generic.List`1[Submission#1+Animal]]

> while (sta.position >=0)
{
    var x = sta.Pop();
    Console.WriteLine($"Popped element type: {x.GetType()}");
}
Popped element type: Submission#3+Camel
Popped element type: Submission#2+Bear
Popped element type: Submission#1+Animal

如果任何 C# 天才有更好的解决方法,请告诉我,因为这是泛型的一个非常烦人的限制。泛型应该像其他语言一样允许继承类。

于 2019-09-10T09:26:58.263 回答