2012-06-27 52 views
3

我最近開始學習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... 
+1

你會知道在編譯時的類型? –

回答

1

不要比較GetType(),因爲它不檢查繼承和東西。 檢查IsAssignableFrom方法 - >http://msdn.microsoft.com/de-de/library/system.type.isassignablefrom.aspx,這是你正在尋找的。

+0

謝謝,這正是我一直在尋找的。使用nawfal推薦的更新的StudentDetails(類型類型)方法實現時,工作得很好。 – hamhut1066

+0

您應該始終包含來自非現場鏈接的相關代碼,以便人們在內容被刪除(它已經被刪除)後仍然可以查看它。 –

0

你可以做可能是這樣的:

請勿使用ArrayList,但在此情況下使用IEnumerable<Person>,因爲所有對象都是從Person派生的抽象類。

private static void StudentDetails(Type filter) 
{ 
    var filteredTypes = people.Where(p=>p.GetType() == filter);    
    .... 
} 
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一個更好的命名。方法名稱應該是一個動詞。

1

如果你知道在編譯時的類型,你可以這樣做:

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

,徹底擺脫StudentDetails方法。 OfType<T>文檔可以找到here

我不確定副手,但是這也可能得到從T派生的類型(在我的示例中,派生自Student)。如果您需要List<T>而不是IEnumerable<T>,則只需撥打ToList()

如果Type參數在運行時確定,該解決方案將工作作爲仿製藥需要編譯時類型的分辨率進行編碼這樣。

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) 
      { 
      } 
     } 
    } 
} 
-1

首先:

接口和抽象類之間的主要不同之處在於您可以在基礎中編寫方法來爲您的代碼提供默認行爲。衆所周知,在接口中是不可能的,因爲在這裏你只提供方法簽名。

您提供的示例有點令人質疑,對於這樣的實現,您確實使用簡單的基類並且沒有抽象類。要提供基類型的集合或字段,您需要使用可以實例化的基類,抽象類不允許的基類。現在

你的問題:

讓我們覺得它低谷。你想擁有一個不能實例化的基礎對象,但是你想提供這個類的一個集合......你看到了這個問題。如果你真的想這樣做,那麼通過許多演員和類型檢查將會有一種方法,但是通過這種方式,整個想法是沒有意義的。一個更好的方法是實現一個接口,但是由於你不能提供任何默認行爲!

我的建議:

爲您的樣品使用普通類Person,任由它繼承的學生。您仍然在基礎中獲得了默認的ToString方法,並在Student類中覆蓋它。 用於將來的代碼。想想,如果你: 需要你的基地(包括集合,模式等)的情況下 - >簡單基礎或接口

需要默認行爲和實例 - >簡單基礎

需要情況下沒有默認的行爲 - >接口

需要默認行爲NO實例 - >摘要

這就是當我需要決定如何實現我的類時需要考慮的事情。

心連心

克里斯托夫

+0

將抽象類型集合到抽象基類中根本不是問題,它不需要任何強制類型轉換或類型檢查。 –