遍历从同一 class 继承的不同对象时的 C# 体系结构问题

C# architecture question when iterating through different objects inherited from the same class

对不起,我真的找不到一个明确的方法来快速解释它。

我正在做一个生成 SpheresTriangles 的项目,我让它们继承自 class Objet 并将它们存储在 List<Objet>.
现在我需要遍历这些对象(使用 foreach),我想在此循环中使用它们的函数 getNormale(???)
问题是 class 球体需要两个参数,而 class 三角形不需要...

我找到了两种方法,但我不知道该用哪一种,如果有更好的方法:

  1. 将抽象函数getNormale(u, v)放入classObjet并覆盖它,问题是Triangle.getNormale(u,v)并不真正需要那些参数。
  2. SphereTriangle 放在两个不同的列表中,List<Sphere>List<Triangle> 遍历每个列表并调用 getNormale(u,v)getNormale() 分别。我不太喜欢这个答案,因为如果我决定添加其他 classes 继承 Objet 我将需要修改这个循环...

您可以检查 cast 并以一种或另一种方式调用它。不需要在祖先中拥有虚拟版本

    static void Main(string[] args)
    {
        List<Shape> shapes = new List<Shape>();
        shapes.Add(new Triangle());
        shapes.Add(new Sphere());
        foreach (var shape in shapes)
        {
            _ = (shape is Triangle) ?
                ((Triangle)shape).GetNormale() :
                ((Sphere)shape).GetNormale(0, 0);
        }
        Console.ReadLine();
    }

由于 getNormale Sphere 需要 2 个参数,Triangle 需要 0 个参数,因此它们之间的关系不足以在 [=15] 中存储 getNormale 的实现=] class。如果有多个 classes 允许 getNormale 的空参数列表,您可以为此使用 sub-class,同样如果有多个 classes 允许 2 个参数对于 getNormale 也可以是它自己的 subclass.

您可以使用 is 运算符来区分这两个对象,并在对它们调用适当的 getNormale 方法之前将它们转换为适当的 class

foreach(var shape in shapes)
{
  string normale;
  if(shape is Triangle)
  {
    normale = ((Triange)shape).getNormale();
  }
  else if(shape is Sphere)
  {
    normale = ((Sphere)shape).getNormale(u,v);
  }
  Console.WriteLine($"Normale: {normale}");
}

或者,如果uv是与对象本身相关的参数(可能u是周长,v是半径),你可以在初始化时知道​​它们,它们应该存储为 Sphere class 中的字段。在这种情况下,您可以不带任何参数调用 getNormale,因为您的 Sphere class 已经可以访问 uv

首先,您真的应该创建一个名为 shape 的抽象 class,SpheresTriangles 都应从中继承。然后添加到 shape 方法 getNormale() 创建 List<shape> 而不是 List<Object>。调用你的基数 class Object 非常混乱,你应该总是让基数 class 尽可能准确地描述派生的

现在,针对问题本身。 It is impossible to override a method with different parameters 这就是您的全部问题。这就是我建议的原因,这实际上取决于您的参数的使用,将参数放入构造函数中,并允许通过 set 方法/ 属性.

更改它们

这是处理此类问题的常用方法。

如果参数不适合成为classes 属性那么你就没有了。您将需要放弃将它们一起调用,而是坚持使用 List<object>,检查每个对象的类型,并相应地获取 Normale,每个类型都有自己的方法和参数。切勿使用冗余参数。这可能非常令人困惑。

double normale;
ICollection<Object> shapes = new List<object>();
//add you shapes here
foreach var shape in shapes{
 if(shape is Spheres)
 {
  normale = ((Spheres)shape).getNormale(u, v);
 }
else
{
 normale = ((Triangles )shape).getNormale();
}
}

您的目标应该是能够迭代您的集合作为基础 class Objet,并且能够在每个对象上调用 GetNormale()(或使用条件逻辑来确定您是否有 Sphere 并调用更具体的方法来自更专业的派生 class).

在 C# 中,使用 'virtual' 关键字作为基础 class 中可以重写的方法,'override' 关键字用于声明派生 [=24] 中的方法=](如果您在派生 class 中有一个具有不同签名的类似方法,则无需重写,因为将被视为单独的)。

using System;
using System.Collections.Generic;
                
public class Program
{
    public static void Main()
    {
        Objet o1 = new Objet("o");
        Sphere s1 = new Sphere("s", 10);
        Triangle t1 = new Triangle("t", 5);

        //  The collection type is Objet, but you can add derived types
        List<Objet> Objets = new List<Objet> { o1, s1, t1 };
        foreach (Objet o in Objets)
        {
            if (o.GetType().Name == "Sphere")
            {
                //  Could use 'if (o is Sphere)' ;)
                //  Special treatment for spheres
                Sphere s = (Sphere)o;
                s.GetNormale("Foo", "Bar");
            }
            else
            {
                //  Could just call this for every item
                o.GetNormale();
            }
        }
    }

    public class Objet
    {
        public string Name {get; set;}
    
        public Objet()
        {
        }
    
        public Objet(string name)
        {
            Name = name;    
        }

        public virtual void GetNormale() =>
            Console.WriteLine(String.Format("Objet prints: {0}", Name));
    }

    public class Triangle : Objet
    {
        public Triangle(string name, int side) : base(name)
        {
            Side = side;
        }
    
        public int Side {get; set;}
    
        //  Override the base class method
        public override void GetNormale() => 
            Console.WriteLine(String.Format("Triangle prints: {0}", Side));
    }

    public class Sphere : Objet
    {   
        public Sphere(string name, int circumference) : base(name)
        {
            Circumference = circumference;
        }
    
        public int Circumference {get; set;}

        //  Method signature is different, no override required
        public void GetNormale(string u, string v) =>
            Console.WriteLine(String.Format("Sphere prints: {0} & {1} & {2}", Circumference, u, v));
    }
}

//  Output
//  Objet prints: o
//  Sphere prints: 10 & Foo & Bar
//  Triangle prints: 5

这称为 'polymorphism',您可以在其中引用一个对象,因为它是基础 class 或派生的 class,具体取决于具体情况。

尝试阅读 'SOLID software design principles',它为 class 继承提供 best-practice 建议。