2009-04-27 50 views
8

所以,對象初始化有各種方便的 - 特別是如果你正在做的LINQ,他們是徹頭徹尾的必要 - 但我不能完全弄清楚這一個:嵌套使用C#對象初始化的

public class Class1 { 
    public Class2 instance; 
} 

public class Class2 { 
    public Class1 parent; 
} 
使用這樣

Class1 class1 = new Class1(); 
class1.instance = new Class2(); 
class1.parent = class1; 

爲初始化:

Class1 class1 = new Class1() { 
    instance = new Class2() { 
     parent = class1 
    } 
}; 

這不起作用,class1的是假想未分配的局部變量。它在Linq中變得更加棘手,當你正在做類似

select new Class1() { ... 

它甚至沒有一個名字來引用它!

我該如何解決這個問題?我可以簡單地不使用對象初始化器來製作嵌套引用嗎?

回答

6

可我根本就沒有使用對象初始化使嵌套引用?

你是對的 - 你不能。會有一個循環; A需要B進行初始化,但B需要先進行A。確切地說 - 你當然可以製作嵌套的對象初始化器,但不能使用循環依賴。

但是你可以 - 並且我建議你應該如果可能的話 - 按如下方式工作。

public class A 
{ 
    public B Child 
    { 
     get { return this.child; } 
     set 
     { 
     if (this.child != value) 
     { 
      this.child = value; 
      this.child.Parent = this; 
     } 
     } 
    } 
    private B child = null; 
} 

public class B 
{ 
    public A Parent 
    { 
     get { return this.parent; } 
     set 
     { 
     if (this.parent != value) 
     { 
      this.parent = value; 
      this.parent.Child = this; 
     } 
     } 
    } 
    private A parent = null; 
} 

構建屬性內的關係有,如果你忘了初始化語句之一,你不能讓一個inconsitent狀態中獲益,很顯然,這是一個不理想的解決方案,因爲您需要兩條語句才能完成一件事。

​​

隨着你只有一個語句要做的事情的性質的邏輯。

a.Child = b; 

或者相反。

b.Parent = a; 

最後用對象初始值設定語法。

A a = new A { Child = new B() }; 
+0

我喜歡這個答案最好的,但它不爲我工作,因爲我離開了那類2實際上是列表,使例子更清晰。它傷透了。 – 2009-04-28 01:25:23

1

此問題不是特定於對象初始值設定項,它是C#語言的一般限制。在明確分配之前,您不能使用局部變量。下面是一個簡單的攝製

Class1 Foo(Class1 c1) { 
    return c1; 
} 

void Example() { 
    Class1 c1 = Foo(c1); 
} 
1

我不認爲這是無論如何要解決這個問題,當應用程序實例Class1的對象,它需要創造了Class2中第一個對象,以便它知道在內存中的參考所在。你可以看到這一點,如果你嘗試以下操作:

 Class1 myClass1 = null; 

     myClass1 = new Class1() 
     { 
      instance = new Class2 
      { 
       parent = myClass1 
      } 
     }; 

這將編譯和運行,但Class2中的parent屬性將是無效的,因爲這是該值在代碼內線已運行的時間,這意味着最內線是第一個被執行。

0

你當然可以使用嵌套的對象初始值設定項,我一直這樣做。

但是,在您的特定情況下,您的對象具有循環引用。在將其分配給另一個之前,您需要完成實例化。否則,你將編譯器交給它無法處理的經典chicken and egg problem

+0

這不是一個雞和雞蛋的問題,至少不是我如何理解初始化符:只是用於聲明一個對象並設置它的屬性的語法糖。 – 2009-04-28 01:17:42

+0

那麼,你的「未分配的本地變量」錯誤告訴我,否則... – 2009-04-28 02:27:37

2

你不能用Object Initializers來做到這一點。

class A 
{ 
    B b; 

    public B B 
    { 
     set 
     { 
      b = value; 
      b.a = this; 
     } 
     get 
     { 
      return b; 
     } 
    } 
} 

class B 
{ 
    public A a; 
} 

調用它:但是,您可以使用屬性格式代碼,這樣的伎倆

var a = new A { B = new B() }; 
0

您的例子並不反映好一流的設計,IMO;這是不適當的凝聚力,並創建一個循環參考。這就是無法在單一表達式中將它們一起實例化的原因。

我建議你回到繪圖板並將你的課程重構爲父母/子女關係。我會在子類上使用構造函數注入,並讓孩子告訴父類,它是它的一個子類。

例如:

public class ParentClass 
{ 
    public List<ChildClass> Children; 
    public void AddChild(ChildClass child) 
    { 
     Children.Add(child); 
     // or something else, etc. 
    } 
    // various stuff like making sure Children actually exists before AddChild is called 
} 

public class ChildClass 
{ 
    public ParentClass Parent; 
    public ChildClass(ParentClass parent) 
    { 
     Parent = parent; 
     Parent.AddChild(this); 
    } 
} 

然後,在你調用代碼:

var parent = new ChildClass(new ParentClass()).Parent; 

而且,是的,這在LINQ的工作原理:

// qry, etc. 
select new ChildClass(new ParentClass()).Parent 

但再怎麼我是否讓所有 ChildClass都有相同的ParentClass 實例? - Andy Hohorst

然後你必須提前知道父類。

var parent = new ParentClass(); 
var child = new ChildClass(parent); 

var parent = new ParentClass(); 
// qry, etc. 
select new ChildClass(parent)