3

我最近开始学习 c# 并遇到了一个问题。我对抽象/接口类不是很熟悉,但了解基本原理和应用。

我目前正在研究 C# 的 OOP,我已经知道 OOP 的机制,已经在 J​​ava 中完成过,但也从未在那里使用过抽象类或接口类。

我的代码的目的是传入对象的 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...
4

6 回答 6

1

如果您在编译时知道类型,则可以使用:

private static void StudentDetails<T>()
{
    ArrayList tmp = new ArrayList();
    foreach (Person p in people)
    {
        if (p is T)
        {
            tmp.Add(p);
        }
    }            
}

并打电话

StudentDetails<Student>();

一些想法:

  1. 您应该更改ArrayList为更强类型的内容,例如List<T>. 在你的情况下List<Person>

  2. StudentDetails一个更好的命名。方法名应该是动词。

于 2012-06-27T12:23:06.390 回答
1

如果您在编译时知道类型,则可以这样做:

var students = people.OfType<Student>().ToList();

并彻底摆脱该StudentDetails方法。OfType<T>文档可以在这里找到。

我不确定,但这也可能获得派生自的类型T(在我的示例中,派生自Student)。仅当ToList()您需要 aList<T>而不是. 时才需要调用IEnumerable<T>

如果Type参数是在运行时确定的,则此解决方案将不起作用,因为泛型需要像这样编码的类型的编译时解析。

于 2012-06-27T12:29:53.150 回答
1

不要比较 GetType() 因为它不检查继承和东西。检查 IsAssignableFrom 方法 -> http://msdn.microsoft.com/de-de/library/system.type.isassignablefrom.aspx,这就是你要找的。

于 2012-06-27T12:20:44.520 回答
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)
            {
            }
        }
    }
}
于 2012-06-27T12:31:34.857 回答
0

你可以做的可能是这样的:

不要使用ArrayList,但IEnumerable<Person>在这种情况下使用,因为所有对象都派生自Person抽象类。

private static void StudentDetails(Type filter)
{
   var filteredTypes = people.Where(p=>p.GetType() == filter);               
    ....
}
于 2012-06-27T12:20:37.967 回答
-1

首先:

接口和抽象类之间的主要区别在于您可以在基类中编写方法来为您的代码提供默认行为。众所周知,这在接口中是不可能的,因为在这里你只提供方法签名。

您提供的示例有点可疑,对于这样的实现,您确实使用简单的基类而没有抽象类。要提供基类型的集合或字段,您需要使用可以实例化的基,这是抽象类所不允许的。

现在你的问题:

让我们考虑一下。你想要一个不能被实例化的基础对象,但是你想提供这个类的一个集合......你看到了问题。如果您真的想这样做,将有一种方法可以通过许多强制转换和类型检查,但是这样整个想法就没有意义了。更好的方法是实现一个接口,但是这样你就不能提供任何默认行为!

我的建议:

对于您的示例,请使用普通类 Person 并让 Student 继承它。您仍然在基础中获得默认的 ToString 方法,并在 Student 类中覆盖它。对于未来的代码。想想你是否:需要你的基础实例(集合、模式等)-> 简单基础或接口

需要默认行为和实例 -> 简单基础

需要实例 没有默认行为 -> 接口

需要默认行为 NO 实例 -> 抽象

当我需要决定如何实现我的课程时,这就是我曾经考虑过的事情。

hth

克里斯托夫

于 2012-06-27T13:03:15.140 回答