2011-09-08 88 views
2

我必須根據構造函數的參數構建一個特殊的類行爲。如果Foo繪畫應該變成永久綠色,如果它是用綠色鉛筆構建(繪製)的。 如果有鉛筆在哪裏使用,Foo應該是透明的...構造函數的優先順序

現在,看下面的代碼。是否有可能修改構造函數「查看」傳入參數對象的實際類型的「輸出」? (其實他們都是 「對象」 S):

class Program 
{ 
    static void Main(string[] args) 
    { 
     object[] objs = { new IndexOutOfRangeException(), MyEnum.Beta, 45, new AssemblyName(), new { Name = "a" } }; 

     for (int i = 0; i < objs.Length; i++) 
     { 
      Console.WriteLine("{0} => {1} ", i, objs[i]); 
     } 
     Console.WriteLine("=========================== "); 
     for (int i = 0; i < objs.Length; i++) 
     { 
      Foo myFoo = new Foo(objs[i]); 
      Console.WriteLine("{0} => {1}", i, myFoo); 
     } 
    } 
} 

public class Foo 
{ 
    object value; 
    string typeName; 

    public Foo(object obj) 
    { 
     value = obj; 
     typeName = "object"; 
    } 

    public Foo(MyEnum enm) 
    { 
     value = enm; 
     typeName = "MyEnum"; 
    } 

    public Foo(int myInt) 
    { 
     value = myInt; 
     typeName = "int"; 
    } 

    public Foo(Exception ex) 
    { 
     value = ex; 
     typeName = "exception"; 
    } 

    public override string ToString() 
    { 
     return string.Format("FOO (object = '{0}'; type = '{1}')", value, typeName); 
    } 
} 

public enum MyEnum 
{ 
    Alpha, 
    Beta 
} 

輸出

0 => System.IndexOutOfRangeException: Index was outside the bounds of the array. 
1 => Beta 
2 => 45 
3 => 
4 => { Name = a } 

=========================== 

0 => FOO (object = 'System.IndexOutOfRangeException: Index was outside the bound 
s of the array.'; type = 'object') 
1 => FOO (object = 'Beta'; type = 'object') 
2 => FOO (object = '45'; type = 'object') 
3 => FOO (object = ''; type = 'object') 
4 => FOO (object = '{ Name = a }'; type = 'object') 

編輯:

正如看到一些答案,我想強調的是,是不是正確的字符串顯示在「類型」變量中,例如使用value.GetType(),但是關於「輸入」正確的構造函數是問題。

換句話說,爲什麼編譯器沒有檢測到正確的類型並將其「重定向」到正確的構造函數?

編輯2:

正如應答者提到的,「辦法」來構造器「內置」在編譯的時候,而不是在運行時。說喜歡他的

將輸出

MyEnum en = MyEnum.Beta; 
Console.WriteLine("Enum example: obj:{0} Foo:{1}", en, new Foo(en)); 
「好」輸出代碼:顯然,像提出

Enum example: obj:Beta Foo:FOO (object = 'Beta'; type = 'MyEnum') 

所以...任何方式「繞過」這種行爲,但在構造函數中運行時的檢測,裏德科普塞...?!

+0

編譯器無法檢測到類型,因爲直到運行時才知道類型。因此它不能確定正確的cctor。 –

+0

@David Neale:謝謝。我需要一個解決方法來「繞過」。 ) – serhio

+0

使用反射('GetType()')獲取類型名稱的建議有什麼問題?當你到達運行時,那是你可以做到這一點的唯一方法。否則 - 爲什麼你循環這些對象?有必要嗎? –

回答

3

爲什麼編譯器沒有檢測到正確的類型並將它「重定向」到正確的構造函數?

這是因爲你傳遞的對象爲System.Object。 (object[] objs = { n...)在編譯時選擇構造函數,而不是在運行時。編譯器可以看到所用變量的聲明,並用於檢查適當的類型。

正如你在另一則留言中提到:

好吧,如果我有對象的大陣,不知道的,先驗的類型?

這正是編譯器這樣工作的原因。它在編譯時不知道你想要哪個構造函數,並且因爲你有一個可以工作的構造函數,所以它被選中。

如果要單獨處理這些特定類型,但仍然將該對象構造爲System.Object,則必須爲構造函數內部的對象添加檢查,並分別處理特定情況。但這不是最易維護的代碼,如果你這樣做的話。

public Foo(object obj) 
{ 
    value = obj; 
    typeName = "object"; 

    // Change typeName if appropriate 
    if (obj != null) 
    { 
     if (obj is MyEnum) 
      typeName = "MyEnum"; 
     else if (obj is int) 
      typeName = "int"; 
     else if (obj is Exception) 
      typeName = "exception"; 
    } 
} 

編輯:

鑑於這種情況,在你真正的代碼,構造很可能會做更多的工作,我會考慮一個工廠方法來處理這個問題。這將允許你使用類似的方法如上,但留下的類型安全構造到位:

// I'd make the object constructor private, to prevent accidental usage: 
private Foo(object obj) { ... 

public static Foo CreateAppropriateFoo(object obj) 
{ 
    if (obj == null) 
     return new Foo(obj); // Use object constructor 
    else 
    {    
     if (obj is MyEnum) 
      return new Foo((MyEnum)obj); 
     else if (obj is int) 
      return new Foo((int)obj); 
     else if (obj is Exception) 
      return new Foo((Exception)obj); 
    } 
} 

這,至少,防止構造邏輯的重複,以及使得它多一點明顯在運行時有一些邏輯發生。

+0

所以,你建議我將所有特定的構造函數替換爲一個大的和常見的......我想我可以避免它... – serhio

+0

@serhio:我不一定會替換它們,但如果你想爲了能夠傳遞一個'Object'並確定類型,你需要在運行時進行檢查。由於我上面提到的原因,編譯器不會處理這個問題。留下其他的構造函數是好的,因爲它允許編譯器在傳遞實際類型時正確地計算出它(即:異常,聲明爲Exception或子類) –

+0

是的,但我會以這種方式複製代碼。由於(錯誤地)提出Devendra D.查萬,我不能,不幸的是,在另一個使用構造函數,以便不重複代碼... – serhio

0

我想你可以通過刪除接受對象參數的ctor(然後所有東西都應該正確綁定到正確的構造函數)或者通過將參數強制轉換爲適當的類型來得到你想要的東西,例如:

var myFoo = new Foo(objs[0] as Exception); 

很可能將ctor與Exception參數一起使用。

編輯:你的問題:爲什麼編譯器沒有檢測到正確的類型並將其「重定向」到正確的構造函數?

我的回答:因爲你傳遞一個對象數組的成員,所以編譯器是權利在處理實際的對象實例作爲對象。

它就像catch塊一樣,必須從最普通的序列到更一般的序列,你有一個通用的捕獲器讓你的ctor接受一個對象,並且你不應該感到驚訝的是從一個對象數組編譯器使用最合適的候選。這就是爲什麼我建議你在調用ctor時進行強制轉換,這樣你可以明確地告訴你要將objs [0]強制轉換爲Exception對象,否則編譯器會將其視爲對象。

+0

好的,如果我有大量的對象,並且不知道,*先驗*他們的類型? – serhio

+0

你正在與風搏鬥。沒有贏家那裏... –