tags:

views:

301

answers:

13

Overloading constructors and methods seems messy, i.e. simply differentiating them by the order and number of parameters. Isn't there a way, perhaps with generics, to do this cleanly so that, even if you just have one parameter (e.g. string idCode / string status) you could still differentiate them?

using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            TheForm tf1 = new TheForm("online", DateTime.Now);
            TheForm tf2 = new TheForm(DateTime.Now, "form1");
        }
    }

    public class TheForm
    {
        public TheForm(string status, DateTime startTime)
        {
           //...
        }

        public TheForm(DateTime startTime, string idCode)
        {
           //...
        }
    }
}
+13  A: 

If you need that many overloads, perhaps your types are handling too much (see Single Responsibility Principle). Personally I rarely need more than one or a few constructors.

Brian Rasmussen
+1 Good point. It should definitely be your first priority to make the API less ambiguous.
Mark Seemann
-1 You didn't even try to answer the question.
Trap
@Trap: I am sorry you didn't like my answer, but I can't see how this doesn't try to answer the question. If you follow the SRP, you generally don't need a lot of overloads. Besides I didn't want to cover the same suggestions as was already provide by other posters.
Brian Rasmussen
@Trap: At the question *How can I put my fingers in the socket?* should the answer detail the actions to do?
serhio
Well maybe it's just me, but when I ask a specific question in SO I always expect to get a concrete answer, rather than a suggestion that something may be or may not be wrong about my code, because one can never know what's the OP's intention.
Trap
@Serhio: I'd downvote that one too because it's not a programming-related question ;)
Trap
@Trap, I see you didn't understand my allusion. At some questions "How" the concrete accepted answer could be "Don't do it" or "Do it in an another way".
serhio
+5  A: 

The only way I can think of to differentiate the construction with a single parameter of a given type is to use a non-instance factory method, either on the type itself or in a factory class.

e.g. (on the type itself)

(untested)

public class TheForm 
{ 
    public static TheForm CreateWithId(string idCode)
    {
    }

    public static TheForm CreateWithStatus(string status)
    {
    }
} 
AdamRalph
right, it just seems like there would be something in the language to handle this in case you really want (or need to have) the constructor to be called "Create"
Edward Tanguay
not sure what you mean... the above methods are not constructors, they are static methods which happen to return a new instance of the type
AdamRalph
I meant it seems like there should be something in the language which enables you to have constructors e.g. like this: Create(string idCode) and Create(string status) so that you don't HAVE to make static methods, perhaps generics or annotations or attributes or metadata of some kind.
Edward Tanguay
@Edward...Having felt myself that way, I agree with you...
The King
@Edward or you want the language to support a feature that not very feasible :) Writing ambigious code as you are suggesting is just a bad idea and luckily the compiler wont help you here :)
Rune FS
+8  A: 

You could consider having a Fluent Builder for the class instead, although it's more work. This would allow you to write something like this:

var form = new TheFormBuilder().WithStatus("foo").WithStartTime(dt).Build();

It's more explicit, but not necessary better. It's definitely more work.

In C# 4, you can optionally write the parameter names when you invoke the constructor:

var form = new TheForm(status: "Foo", startTime: dt);
Mark Seemann
+1  A: 

Constructor Forwarding!

this. __curious_geek
+1  A: 

Use helper initialization classes to communicate the semantics of your overloads.

So, for instance, define

public class TheForm
{
    public class TheForm(ById initializer)
    {
        //...
    }

    public class TheForm(ByStatus initializer)
    {
        //...
    }

    // ... 

    public class ById
    {
        public ById(DateTime startTime, string idCode)
        // ...
    }

    public class ByStatus
    {
        public ByStatus(string status, DateTime startTime)
        // ...
    }
}

However, prefer using classes which are more generally usable if you can, not just for initalialization. You may want to factor your classes in a different way instead. I sense the possibility of a code smell: does your TheForm class contain too much business logic? Might you want to split out an MVC Controller, for instance?

Pontus Gagge
A: 

Isn't this where inheritence comes in? Just have TheForm as a base class and then TheFormWithID and TheFormWithStatus child classes. Have their constructors take string ID and string Status respectively passing back the DateTime value to the base class.

I haven't got any coding tools infront of me so please excuse the syntax. I'm sure that you'll figure it out.

using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            TheForm tf1 = new TheFormWithStatus(DateTime.Now, "online");
            TheForm tf2 = new TheFormWithID(DateTime.Now, "form1");
        }
    }

    public class TheForm
    {
        public TheForm(DateTime startTime)
        {
           //...
        }

    }

    public class TheFormWithID : TheForm
    {
        public TheFormWithID (DateTime startTime, string idCode) : TheForm (startTime)
        {
           //...
        }
    }

    public class TheFormWithStatus : TheForm
    {
        public TheFormWithStatus (DateTime startTime, string status) : TheForm (startTime)
        {
           //...
        }
    }
}

Or have TheForm as an abstract class.

ChrisBD
+2  A: 

Before Fluent builders we sometimes managed to get around with parameter objects or setup objects:

public class FormSetup {
  public string Status ...
  public string Id ...
}


var frm = new MyForm(new FormSetup { Status = "Bla", ... });
flq
+1  A: 

In C# (like in many other programming languages) in this case you should use Factory Methods. Something like this:

class TheForm
{
  public static TheForm CreateFromId(string idCode);
  public static TheForm CreateFromStatus(string status);
}

or fiction parameters:

class TheForm
{
  public TheForm(string idCode, int);
  public TheForm(string status);
}

Or you can use Eiffel ;):

class THE_FORM create
   make_from_id, make_from_status
feature
  ...
end
Sergey Teplyakov
+1  A: 

We use properties instead of overloading constructors, it's quite clean and easy to implement:

public class x {
  public string prop1 {get;set;}
  public DateTime prop2 {get;set;}
  ...
}

and then fill just the properties you need at instantiation time (and/or later)

var obj = new x() {
  prop1 = "abc",
  prop2 = 123
};

The benefit with this is it works with .Net 3.5 and makes it really clear what is being set. (as opposed to var obj = new x("abc", 123, true, false, ... etc) where you have to guess the meaning of each value, which can get really hairy when there are many overloads)

Will
A: 

I am not getting what "messy" you found in multiple constructors. I felt the static methods for returning an instance of the object also a probable alternate.

But, if somebody want to have the fancy of a single constructor and still have different implementations, we can think of passing an object derived from some interface as the input to the constructor and might check the type of the input to create an instance. This is kind of an abstract factory in this case.

In one place we have a class like the following:

using System;

namespace MyApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            base1 t1 = new type1();
            class1 c1 = new class1(t1);
            base1 t2 = new type2();
            class1 c2 = new class1(t2);
            //.....
        }
    }

    public class class1
    {
        public class1(base1 mytype)
        {
           switch(mytype.type)
               case mytype.types.type1
                   return createObjectOftype1();
               case mytype.types.type2
                   return createObjectOftype2();
               case mytype.types.type3
                   return createObjectOftype3();
        }

        public class1 createObjectOftype1()
        {
            //....
        }

        public class1 createObjectOftype2()
        {
           //...
        }

        public class1 createObjectOftype2()
        {
           //...
        }

    }


    public class base1
    {
        publlic Enum Types {0 "type1",.... 
    }

    public class type1:base1
    {
        //.....
    }

    public class type2:base1
    {
        //.....
    }
}
Kangkan
+5  A: 

The new object initialization feature of .NET 3.0 is more flexible than an overloaded constructor. Here is a simple example:

public class Item
{
    public string Name {get; set;}
    public int Index {get; set;}
    public string Caption {get; set;}
} 

As it is written now, we can do the following in code:

var x = new item {Name=”FooBar”};
var x = new item {Name=”FooBar”, Index=”1”, Caption=”Foo Bar”};

I would only add an overloaded constructor to the class Item if I want to add functionality during property initialization. For example:

public class Item
{
    public Item() {}

    public Item(string name)
    {
        Name = name;
        Caption = name; //defaulting name to caption
    }

    public Item(string name, int index) : this(name)
    {
        Index = index;
    }

    public Item(string name, int index, string caption) : this(name, int)
    {
        Caption = caption;
    }

    public string Name {get; set;}
    public int Index {get; set;}
    public string Caption {get; set;}
} 

Note: If this was a child class, I could have chained to a parent constructor with the “base” keyword.

If I am writing a “configuration” type of class, I use Fluent Methods in place of Overloaded constructors.

For example, if I added these methods to the Item class:

public Item WithName(string name)
{
    Name = name;
    return this;
}
public Item WithIndex(int index)
{
    Index = index;
    return this;
}
public Item WithCaption(string caption)
{
    Caption = caption;
    return this;
}

I could write code like this:

var x = new Item().WithName(“FooBar”).WithIndex(“99”).WithCaption(“Foo Bar”); 
fremis
+1 Use the built in language features (constructor chaining and object initialisation) instead of making more work for yourself by reinventing the wheel.Edit: I should mention that object initialisation is *not* a .NET 3.5 feature. Rather, it is a feature of C# 3.0
alimbada
alimbada, thanks for the heads up on the 3.0 feature.
fremis
No problem. A lot of people don't realise that the .NET version is not in sync with the C# language version and neither is it in sync with the CLR version. It's a recipe for massive confusion. :-)
alimbada
A: 

Whether you're talking about constructors or not, overloading's pretty limited, and when you start to run up against its limits, that's a hint that it's not the right tool for the job.

It's worth looking at a well-designed API that uses overloading to get a sense of what kind of job the tool is good for. XmlReader.Create is a good example: It supports twelve different overloads. Twelve! And yet, it's actually completely sensible: when you look at them all, they boil down to what would, in Python, be a single calling signature with optional parameters:

XmlReader.Create(input [, settings [, parser_context]])

input, to this method, can be a string containing a URL or filename, a TextReader, or a Stream. But irrespective of its data type, it's still fundamentally the same thing: the source of the data that the XmlReader is going to read.

Now let's look at your case. Forget about data types for a moment. There's clearly some functional difference between a status and an idCode in your application. Your form is going to behave one way if it's given a status and another if it's given an idCode. The API that you're proposing conceals this functional difference. It should be illuminating it.

I would first consider the simplest possible approach, which uses no overloads at all:

TheForm(string idCode, string status)

Make your constructor throw an exception if both values are provided (or if both are null). Note that they're mutually exclusive in the documentation. Call it a day.

My second choice would be:

enum FormType
{
   IdCode,
   Status
};

TheForm(FormType type, string data)

This is less concise, but it has the very great merit of making the fact that this method supports multiple mutually-exclusive modes explicit.

I called that enum FormType because it seemed like a sensible name, given what I know so far, and the fact that this method's a constructor. But whenever you contemplate creating an enum to determine the type of an instance, you should at least consider the possibility that you should really be creating a type to determine the type of an instance:

class TheFormWhatUsesIdCode : TheForm {...}
class TheFormWhatUsesStatus : TheForm {...}

The functional difference between idCode and status probably relates to a functional difference between a form instantiated with idCode and a form instantiated with status. And that strongly suggests that they should be subclasses.

In all of this analysis, I've never once considered the possibility of doing what you actually asked for, which is to provide multiple overloads. I don't think overloading is the right tool for this job. If idCode were an int and status were a string I still wouldn't think that overloading were the right tool for this job, though I probably wouldn't have ended up noticing it until I had a lot of code I needed to refactor.

Robert Rossney
+1  A: 

Here's an example:

Timespan.FromMilliseconds(double)
Timespan.FromSeconds(double)
Timespan.FromMinutes(double)
Timespan.FromHours(double)
Timespan.FromDays(double)
280Z28