2014-09-25 145 views
3

想象一下,原則上可以通過指定兩個屬性中的一個的值來創建一個類,這兩個屬性的類型恰好相同。下面的代碼使用的named and optional parameters二者的結合構造區分完成此:使用命名參數和可選參數來區分構造函數

class Program 
{ 
    static void Main() 
    {   
     //Note: these 2 ctors are distinguished only by the argument naming convention: 
     thing thingWithMass = new thing(mass: 10); 
     thing thingWithVolume = new thing(vol: 25); 
    } 

    class thing 
    { 
     int Density = 3; 
     int Mass; 
     int Vol; 
     public thing(int mass) 
     { 
      Mass = mass; 
      Vol = Mass/Density; 
     } 

     // Note the use of the optional variable to distinguish this ctor: 
     public thing(int vol, bool isVol=true) 
     { 
      Vol = vol; 
      Mass = Vol * Density; 
     } 
    } 
} 

所以(有些奇怪)這個代碼編譯和完美的作品,但它是不好的形式?這看起來有點像詭計,我想知道是否有一種潛伏的危險對我來說並不明顯?它有味道嗎?

注:在這種特殊情況下,我認識到,我也只能做到基本相同的事情有一個構造函數,看起來像這樣:

public thing(int mass=0, int vol=0) //plus a couple of if() statements in the body 

但在我的實際情況有相當涉及其他一些參數,並將它們全部組合成一個構造函數會變得有點笨拙和難以閱讀。

+1

我會說它聞起來有點。任何使用這個課程的人都必須知道如何處理這個詭計,否則他們可能會收到意想不到的結果。 – JLRishe 2014-09-25 16:22:17

+0

我認爲這將是最好的顯示你的真實代碼,因爲坦率地說,現在我想問你爲什麼甚至讓一個類(一個引用類型btw)包裝一個整數值。 – Crono 2014-09-25 17:26:43

+0

@Crono:我的班遠比這更復雜;對於這個例子我只是刪除了一些不必要的東西來演示構造邏輯。 – kmote 2014-09-25 17:45:59

回答

3

如果你的類有非常不同的邏輯和相互衝突的類型的參數許多構造,可以考慮使用靜態工廠方法:

public static Thing CreateFromMass(int mass) 
{ 
    return new Thing(mass, 0); 
} 

public static Thing CreateFromVol(int vol) 
{ 
    return new Thing(0, vol); 
} 

你可以讓你的構造函數非公如果使用工廠方法是這樣的。

不推薦基於參數名來區分構造函數,因爲它在C#中非常罕見。請注意,你也被迫使用可選參數的技巧來實現這一點 - 一個明確的指示,你做錯了什麼。

+0

這是一個很好的建議。謝謝! – kmote 2014-09-25 16:33:09

1

海事組織這是一種氣味。如果消費者撥打thing(10, false),該怎麼辦?這具有創建thing錯誤值的意想不到的結果。

由Athari描述我能想到的兩種可能的解決方案

1)使用的工廠。

2)創建質量和體積的類型。例如,

class Mass 
{ 
    private readonly int _mass; 
    public Mass(int mass) { _mass = mass; } 
    public int Value { get { return _mass; } } 
} 

class Volume 
{ 
    private readonly int _volume; 
    public Mass(int volume) { _volume = volume; } 
    public int Value { get { return _volume; } } 
} 

然後你可以改變你的簽名,以

thing(Volume volume) 
thing(Mass mass) 

在回答你關於不與第二種方法工作簡單的算術運算評論,你可以定義隱式轉換和從intMassVolume

abstract class Number 
{ 
    public static implicit operator int(Number number) 
    { 
     return number.Value; 
    } 

    public abstract int Value { get; set; } 
} 

internal class Mass : Number 
{ 
    public override int Value { get; set; } 
    public static implicit operator Mass(int val) { return new Mass(){ Value = val }; } 
} 

internal class Volume : Number 
{ 
    public static implicit operator Volume(int val) { return new Volume(){ Value = val }; } 
    public override int Value { get; set; } 
} 

var mass = new Mass { Value = 10 }; 
var volume = new Volume { Value = 20 }; 
int product = mass * volume; // should work 
mass = 10 * 20; // should also work 
+0

np,很高興我能幫到你! – 2014-09-25 16:34:18

+0

另一個偉大的建議(和關於意想不到的後果的一個偉大的觀點)。謝謝! – kmote 2014-09-25 16:34:39

+0

雖然我仍然認爲你的建議很有用,但它有一些我不舒服的後果。例如,像「質量=體積×密度」這樣簡單的方程必須轉化爲質量=新的質量(體積。值*密度。值),這將使更復雜的方程難以閱讀。但是,謝謝你幫助我在盒子外面思考! – kmote 2014-09-25 17:09:43