2014-09-25 146 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