对不起这个标题,我真的找不到明确的方法来解释它。
我正在做一个生成Spheres
和Triangles
的项目,我让它们从类Objet
继承并存储在List<Objet>
中
现在我需要迭代这些对象(使用foreach
(,并且我希望在这个循环中使用它们的函数getNormale(???)
问题是类Sphere需要两个参数,而类Triangle不。。。
我找到了两种方法,但我不知道该用哪一种,如果有更好的方法:
- 将抽象函数
getNormale(u, v)
放在类Objet
中并覆盖它,问题是Triangle.getNormale(u,v)
实际上并不需要这些参数 - 将
Sphere
和Triangle
放在两个不同的列表中,List<Sphere>
和List<Triangle>
分别遍历它们,并分别调用getNormale(u,v)
和getNormale()
。我真的不喜欢这个答案,因为如果我决定添加继承Objet
的其他类,我将需要修改这个循环
由于getNormale
为Sphere
需要2个参数,为Triangle
需要0个参数,因此它们之间的关系不足以将getNormale
的实现存储在Objet
类中。如果有多个类允许getNormale
的参数列表为空,则可以为此使用一个子类,同样,如果有多个子类允许getNormale
的2个参数,也可以是其自己的子类。
您可以使用is
运算符来区分这两个对象,并在对它们调用适当的getNormale
方法之前将它们强制转换为相应的类
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}");
}
或者,如果u
和v
是与对象本身相关的参数(可能u是周长,v是半径(,并且您可以在初始化时知道它们,那么它们应该作为字段存储在Sphere
类中。在这种情况下,您可以在没有任何参数的情况下调用getNormale
,因为您的Sphere
类已经可以访问u
和v
您的目标应该是能够将集合迭代为基类Objet,并能够对每个对象调用GetNormal(((或者使用条件逻辑来确定您是否有Sphere,并从更专业的派生类中调用更具体的方法(。
在C#中,对基类中可以重写的方法使用"virtual"关键字,并使用"override"关键字声明派生类中的方法(如果派生类中有一个具有不同签名的类似方法,则无需重写,因为这将被视为单独的方法(。
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
这被称为"多态性",根据具体情况,可以将对象称为基类或派生类。
试着阅读"SOLID软件设计原则",它为类继承提供了最佳实践建议。
您可以检查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();
}
首先,您确实应该创建一个名为shape
的抽象类,Spheres
和Triangles
都应该从中继承。然后向shape
添加创建List<shape>
而不是List<Object>
的方法getNormale()
。调用基类Object
是非常令人困惑的,您应该始终使基类尽可能准确地描述派生的
现在,为了问题本身。用不同的参数重写一个方法是不可能的,这就是你真正要问的问题。这就是为什么我建议将参数放入构造函数中,并允许通过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();
}
}