2012-01-17 29 views
11

如果我已經創建瞭如下僱員對象(簡化的)...自定義C#對象是否可以包含與其自身相同類型的屬性?

public class Employee 
    { 
     public Employee() 
     {  
     } 

     public String StaffID { get; set; } 
     public String Forename { get; set; } 
     public String Surname { get; set; } 
    } 

...這將是可以接受的在僱員對象的另一屬性與類型也正在僱員保留經理的細節(如下所示)?

public class Employee 
    { 
     public Employee() 
     {  
     } 

     public String StaffID { get; set; } 
     public String Forename { get; set; } 
     public String Surname { get; set; } 

     public Employee Manager { get; set; } 
    } 

此外,什麼是實例爲經理財產員工對象的最佳方式?顯然在構造函數中包含this.Manager = new Employee();將導致無限循環。是經理繼承僱員是最好的方式(即使所有的屬性將是相同的)?

+3

@FelixK:

class Program { static void Main(string[] args) { A a = new A(new A()); } } public class A { public string Name { get; set; } public A a; public A() { } public A(A _a) { a = _a; } } 

現在你可以在main()函數一樣使用它。這有點苛刻,它的一個很好的問題,並採取了一些興趣閱讀這個* ..在構造函數將導致無限循環*。記住所有不是專家 – V4Vendetta 2012-01-17 10:18:09

+0

@ V4Vendetta這是事實,我們並不都是專家。但是,當我遇到問題或問題時,我會測試一些解決導致問題的任務的方法。 – 2012-01-17 10:33:35

+0

@FelixK。是的,我確實嘗試過,它編譯得很好 - 這就是爲什麼我的問題是它是「可接受的」而不是「它會工作」 - 我想檢查這是否是好的做法或不是什麼。碰巧,下面關於對象實例化的解決方案几乎與我所得出的結論一樣,但又相對缺乏經驗,我想確保我正常運行。 – triplestones 2012-01-17 11:01:25

回答

17

一個對象可以確實有一個對自己類型的對象的引用。

這是大多數Node類型對象的實現方式。

至於實例化 - 您可以傳入Employee對象以用作管理器(傳遞null沒有管理器)。構造器可以有多個過載:

public Employee(Employee manager) 
{ 
    this.Manager = manager; 
} 
+1

+1,與'Node'類型進行比較。 – ken2k 2012-01-17 10:06:19

+0

...但顯然你不應該無條件地初始化你的構造函數中的屬性/字段(因爲這會導致StackOverflowException或OutOfMemoryException,這取決於對象的大小,分配的堆棧大小和整體有效內存)。 – Nuffin 2012-01-17 10:09:03

+1

@Tobias上面的代碼不會導致任何異常。如果你用'this.Manager = new Employee()'初始化它會導致一個。 – 2012-01-17 10:12:23

7

是的,一個對象可以包含對同一類的其他對象的引用。

其次,我不會創建在cunstructor一個新員工,但注入這樣的:

public class Employee 
{ 
    public Employee(Employee manager) 
    { 
     this.Manager = manager; 
    } 

    public String StaffID { get; set; } 
    public String Forename { get; set; } 
    public String Surname { get; set; } 

    public Employee Manager { get; set; } 
} 
+0

+1構造注入! – 2012-01-17 10:08:08

1

它的工作原理,你可以嘗試某事物像:

public class A 
{ 
    public A test { get; set; } 
} 
2

是的,你可以有EmployeeEmployee並不會造成死循環,在默認情況下Employee對象Manager屬性將是null

1

特別是關於構建問題(我已經+1了Odeds答案) - 正如你所說在構造函數中構造一個實例是一個壞的舉動。

但後來問自己 - 爲什麼你需要反正。在你的Manager/Employee案例中 - 你不能總是確定一個僱員總是有一個經理,如果他們不這樣做,那麼你不應該使用一個空實例來表示這個,而是一個空。

當你的類型在屬性上有公共get/set訪問器時,通常你可能會從某些外部源加載這些對象樹,在這種情況下你沒有什麼可擔心的。同樣,您可以擁有一個構造函數,以接受其他Employee實例的經理/員工關係等。

您還應該檢查該構造函數中的循環關係 - 即一個員工不能成爲某人的經理和他們的員工 - 試着爲孩子走親子關係,看看它是否結束!

0

首先,答案是是的一個對象可以有一個字段包含自己的一個實例。它甚至可以接受的方法或返回相同的類的實例,它甚至可以依靠自身在類的定義,如:

public class Person : IComparable<Person> //legal, recursive definition 
{ 
    //fields (or properties) that are of type Person 
    public Person Father; 
    public Person Mother; 
    public List<Person> Children; 

    // method that takes a Person as a parameter 
    public bool IsParent(Person potentialParent) 
    { 
     .... 
    } 

    //method that returs a Person 
    public Person Clone() 
    { 
     //TODO: real implementation coming soon 
    } 

    public Person(){} 

    //constructor that takes persons as arguments 
    public Person(Person father, Person Mother) 
    { 
     Father = father; 
     Mother = mother; 
    } 
} 

默認情況下,所有的參考值是null「D所以你除非你自己創建一個構造函數,否則不會有構造函數問題。所以,是的,可以有一些循環引用和無限循環的問題(每個父母有孩子,有孩子,有父母等),但通常他們可以平凡地檢測和避免。

我遇到這類問題的唯一時間是當我在循環引用的對象上使用XML(或其他基於文本的)序列化時。

3

不是可能的唯一情況是struct;一個struct包含直接(而不是一個固定大小的參考數據),所以Employee結構的大小將必須是「其他領域的大小加上僱員的大小」,這是圓形。

特別是你不能有: - :

結構成員 'Foo.foo'

struct Foo { 
    Foo foo; 
} 

(或其他任何將導致圓形大小)編譯器響應'Foo'類型會導致結構佈局中的循環

但是,在所有其他情況下,它都是好的;在初始化的問題上,我會說:只是最初不分配它,讓調用者通過屬性分配一個值。

0

我試過這種方式,它的工作對我來說:

class Program 
{ 
    static void Main(string[] args) 
    { 
     A a = new A(new A()); 
     a.Name = "Roger"; 
     a.a.Name = "John"; 
     Console.WriteLine("{0}, {1}", a.Name, a.a.Name); 
    } 
} 
相關問題