Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# constructors with same parameter signatures

Tags:

c#

.net

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?

like image 892
Doogal Avatar asked Jan 28 '09 15:01

Doogal


5 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;
    }
}
like image 113
Sean Bright Avatar answered Sep 30 '22 01:09

Sean Bright


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.

like image 32
Adam Wright Avatar answered Sep 30 '22 00:09

Adam Wright


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

like image 45
Brian Avatar answered Sep 30 '22 02:09

Brian


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.

like image 27
tvanfosson Avatar answered Sep 30 '22 02:09

tvanfosson


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"};
like image 31
Gerrie Schenck Avatar answered Sep 30 '22 00:09

Gerrie Schenck