我最近开始学习c#并遇到了一个问题。我对抽象/接口类不太熟悉,但对基本原理和应用程序有所了解。
我目前正在考虑使用OOP进行c#,我已经了解了OOP的机制,用Java完成了它,但从未在那里使用过抽象或接口类。
我的代码的目的是传入一个对象的ArrayList(公共父类的两个子节点)并打印出那些特定类的对象。这是有效的,但我很想知道如果我可以使用相同的方法打印出父类的所有子对象,如果父类是抽象的。
父类
abstract class Person
{
protected string Name { get; set; }
protected int Age { get; set; }
public override string ToString() { return "Person:" + Name + ", " + this.Age; }
}
儿童班
class Student : Person
{
private int studID { get; set; }
private string school { get; set; }
public Student() { }
public Student(string name, int age, int studID, string school)
{
this.Name = name;
this.Age = age;
this.studID = studID;
this.school = school;
}
public override string ToString()
{
string s = "Student:" + Name + ", " + Age + ", " + studID + ", " + school;
return s;
}
}
方法调用
private static void StudentDetails(object type)
{
ArrayList tmp = new ArrayList();
//display all
//foreach (Person p in people) tmp.Add(p);
foreach (Person p in people)
{
if (type.GetType() == p.GetType())
{
tmp.Add(p);
}
}
//etc...
答案 0 :(得分:1)
不要比较GetType(),因为它不检查继承和东西。 检查IsAssignableFrom方法 - > http://msdn.microsoft.com/de-de/library/system.type.isassignablefrom.aspx,这就是你要找的东西。
答案 1 :(得分:1)
如果您在编译时知道类型,可以使用:
private static void StudentDetails<T>()
{
ArrayList tmp = new ArrayList();
foreach (Person p in people)
{
if (p is T)
{
tmp.Add(p);
}
}
}
并致电
StudentDetails<Student>();
一些想法:
您应该将ArrayList
更改为更强类型的内容,例如List<T>
。在您的情况下List<Person>
。
为StudentDetails
提供更好的命名。方法名称应为动词。
答案 2 :(得分:1)
如果您在编译时知道类型,可以这样做:
var students = people.OfType<Student>().ToList();
完全摆脱StudentDetails
方法。可以找到OfType<T>
文档here。
我不确定副手,但这也可能会获得源自T
的类型(在我的示例中,派生自Student
)。仅当您需要ToList()
而不是List<T>
时才需要IEnumerable<T>
来电。
如果在运行时确定了Type
参数,则此解决方案将 不 工作,因为泛型需要编译时解析要编码的类型。
答案 3 :(得分:0)
您可以可能之类的内容:
不要使用ArrayList
,但在这种情况下使用IEnumerable<Person>
,因为所有对象都是从Person
抽象类派生的。
private static void StudentDetails(Type filter)
{
var filteredTypes = people.Where(p=>p.GetType() == filter);
....
}
答案 4 :(得分:0)
你可以使用你的基类来做到这一点(尽管它是抽象的):
class Program
{
static void Main(string[] args)
{
List<Person> persons = new List<Person>();
persons.Add(new Student("John", 18, 1, "Stanford"));
persons.Add(new Student("Matt", 20, 2, "Stanford"));
persons.Add(new Teacher("Alice", 30));
StudentDetails(persons);
}
private static void StudentDetails(List<Person> people)
{
foreach (Person p in people)
{
try
{
Student s = (Student)p;
Console.WriteLine(s.ToString());
}
catch(InvalidCastException e)
{
}
}
}
}
答案 5 :(得分:-1)
首先:
Interface和Abstract类之间的主要区别在于您可以在基础中编写方法以为代码提供默认行为。众所周知,在接口中是不可能的,因为在这里你只提供方法签名。
您提供的示例有点疑问,对于此类实现,您确实使用简单的基类而没有抽象类。要提供基类型的集合或字段,您需要使用可以实例化的基础,这是抽象类不允许的。
现在问题:
让我们认为它是低谷。您希望拥有一个无法实例化的基础对象,但您想提供此类的集合...您会看到问题所在。如果你真的想要这样做,那么通过许多演员表和类型检查将会有一种方法,但是通过这种方式,整个想法毫无意义。更好的方法是实现一个接口,但是这样你就无法提供任何默认行为!
我的建议:
对于您的示例,请使用普通类Person,并让Student继承它。您仍然在基础中获得默认的ToString方法,并在Student类中覆盖它。 对于未来的代码。想想你是否: 需要你的基础实例(集合,模式等) - &gt;简单的基础或接口
需要默认行为和实例 - &gt;简单的基础
需要实例没有默认行为 - &gt;接口
需要默认行为否实例 - &gt;摘要
当我需要决定如何实现我的类时,这就是我经常考虑的事情。
HTH
了Christoph