C# constructors with same parameter signatures

I'm sure this must be a common problem. I've got a class that in an ideal world would have the following constructors

public Thing(string connectionString)

public Thing(string fileName)

Obviously this isn't allowed because the signatures are the same. Does anybody know of an elegant solution to this problem?

Answers


You can used the named constructor idiom:

public class Thing
{
    private string connectionString;

    private string filename;

    private Thing()
    {
        /* Make this private to clear things up */
    }

    public static Thing WithConnection(string connectionString)
    {
        var thing = new Thing();
        thing.connectionString = connectionString;
        return thing;
    }

    public static Thing WithFilename(string filename)
    {
        var thing = new Thing();
        thing.filename = filename;
        return thing;
    }
}

Well, there are several potentials - what's considered elegent depends on the usage scenario.

  • Static factory methods, that call into a private constructor.

    static Thing thingWithFileName(string fileName)
    
  • Create a different type for one of the parameters, or use a builtin. Rather than a string fileName, you could use a System.IO.FileStream. This is also more type safe, as I can't accidently pass the wrong data into the wrong static method, or field.

  • Pass a second parameter to the constructor, either an enum or a boolean, indicating the intent of the first parameter

    enum ThingType { FileName, ConnectionString }
    Thing(string str, ThingType type) ...
    
  • Subclass Thing, so you have a ConnectionTypeThing and a FileBackedThing

  • Completely eliminate Thing doing it's connection, and have preconnected data sources provided. So you end up with

    Thing(InputStream dataSource)
    

    or something analogous.

My "elegance" money goes on either the first or second suggestions, but I'd need more context to be happy with any choice.


You can make all the constructors private and create factory methods (static methods on the class like CreateFromConnectionString()).


These actually seem like different "things" to me, either a class associated with a file or a class associated with a database. I'd define an interface, then have separate implementations for each. Use a Factory to generate the correct implementation.

A hint that you may need to change your design is if your methods have to decide whether they are working with a file or a database before they perform the required action. If this is the case, then separating into different classes would be the way I would go.

public interface IThing
{
   ... methods to do the things that Things do
}

public class FileThing : IThing
{
  ... file-based methods
}

public class DatabaseThing : IThing
{
  ... database-based methods
}

public static class ThingFactory
{
     public IThing GetFileThing( string name )
     {
         return new FileThing( name );
     }

     public IThing GetDatabaseThing( string connectionString )
     {
         return new DatabaseThing( connectionString );
     }
}

If you had common behavior you could alternatively define an abstract class containing the default/common behavior and derive from it instead of/in addition to the interface.


Make two public properties ConnectionString and FileName and then use these to fill your object.

In C# you can use an object initalizer. Like this:

Thing thing = new Thing{FileName = "abc", ConnectionString = "123"};

Here are some workarounds.

Have one constructor that takes a connection string, and then have a factory method on the class that takes filename. Something like this:

public static Thing CreateThing(string fileName)

this method can call a private parameter less constructor, and you can take it from there.

Another option, is to have an enum that has two types in it. FileName and ConnectionString. Then just have one constructor that takes a string, and the enum. Then based on the enum you can determine which way to go.


I like static constructor-functions:

class Thing
{
   public static Thing NewConnection(string connectionString)
   {
       return new Thing(connectionString, true);
   }

   public static Thing NewFile(string fileName);
   {
        return new Thing(fileName, false);
   }
}
.
.
.
{
    var myObj = Thing.NewConnection("connect=foo");
    var Obj2 = Thing.NewFile("myFile.txt");
}

(not shown, but straight-forward, the implementation of the Thing-Constructor with an extra boolean parameter).


Need Your Help

Is there an equivalent of java.util.regex for "glob" type patterns?

java glob

Is there a standard (preferably Apache Commons or similarly non-viral) library for doing "glob" type matches in Java? When I had to do similar in Perl once, I just changed all the "." to "\.", the...

Calculating Text Width In ActionScript And Flex

apache-flex flash actionscript-3 air

I'm trying to calculate how WIDE to make my button, based on the text that it will contain, and when I try to google for how to calcuate something as simplistic as the WIDTH OF SOME TEXT, I go cros...