Jonathan.
Jonathan.

Reputation: 55534

multiple constructors in C#

I have class which needs data, this can be as bytes or as a file path.

At the moment I read the file into a byte array and then setup the class. And in another seperator it sets up the class directly from bytes passed as parameter.

I'd like the first constructor (file path) to call the second (bytes), something like:

    public DImage(byte[] filebytes) : this()
    {
        MemoryStream filestream = null;
        BinaryReader binReader = null;
        if (filebytes != null && filebytes.Length > 0)
        {
            using (filestream = new MemoryStream(filebytes))
            {
                if (filestream != null && filestream.Length > 0 && filestream.CanSeek == true)
                {
                    //do stuff
                }
                else
                    throw new Exception(@"Couldn't read file from disk.");
            }
        }
        else
            throw new Exception(@"Couldn't read file from disk.");
    }


    public DImage(string strFileName) : this()
    {
        // make sure the file exists
        if (System.IO.File.Exists(strFileName) == true)
        {
            this.strFileName = strFileName;
            byte[] filebytes = null;
            // load the file as an array of bytes
            filebytes = System.IO.File.ReadAllBytes(this.strFileName);
            //somehow call the other constructor like
            DImage(filebytes);                         
        }
        else
           throw new Exception(@"Couldn't find file '" + strFileName);

    }

So how do I call the first constructor (to save copying and pasting the code), from the second?

Upvotes: 1

Views: 1117

Answers (3)

Carsten
Carsten

Reputation: 11596

I could imagine implementing 3 constructors:

  1. Accepting a System.Stream that can be accessed by a System.IO.StreamReader
  2. Accepting an array of bytes, wrapping it into an System.IO.MemoryStream and calling the first constructor.
  3. Accepting an file name, loading it using a System.IO.FileStream and calling the first constructor.

Here's an example:

using System.IO;

// ...

public DImage(Stream Stream)
{
    using (var reader = new StreamReader(Stream))
    {
        // Read the image.
    }
}

public DImage(byte[] Bytes) 
    : this(new MemoryStream(Bytes))
{
}

public DImage(string FileName) 
    : this(new FileStream(FileName, FileMode.Open, FileAccess.Read))
{
}

This also makes it easier to handle exceptions. The constructor of FileStream will throw an System.IO.FileNotFoundException, if the file does not exist, so you can handle it from wherever you are instancing the DImage-class:

try
{
    var image = new DImage(@"C:\Test.img");
}
catch (System.IO.FileNotFoundException e)
{
    // The image could not be found.
}
catch (Exception e)
{
    // Something else happened.
}

This method uses the keyword this behind the constructor to delegate special construction cases to the default constructor. It has two advantages:

  1. Reduce required code by removing code douples.
  2. Increasing reuseability, by defining a default constructor, accepting a System.Stream. Clients can either call the constructors to load images from memory chunks or file system entries, or they can implement their own stream to provide custom datasources (like DB BLOBs, NetworkStreams, ...).

Upvotes: 0

Jon Skeet
Jon Skeet

Reputation: 1499760

I would actually suggest exposing two static methods:

public static DImage FromFile(string filename)
{
    // Load image, then call constructor
}

public static DImage FromData(byte[] data)
{
    // Do anything you need to, then call the constructor
}

The exact form of the constructor is up to you, but I'd probably make it private. Using static factory methods leads to clearer code in my experience, and means you can defer calling an actual constructor until you're actually ready to do the work. This helps in terms of making fields readonly etc. The big downside is the lack of support for inheritance.

Upvotes: 4

ken2k
ken2k

Reputation: 48965

You could create a private method taking a byte[] as parameter, say ProcessImage(byte[] myparam), that would be called by both constructors to process your bytes.

Side note: you might want to consider using a stream instead of a byte[].


Quick example:

public DImage(byte[] filebytes) : this()    // Remove if no parameterless constructor
{
    MemoryStream filestream = null;
    BinaryReader binReader = null;
    if (filebytes != null && filebytes.Length > 0)
    {
        using (filestream = new MemoryStream(filebytes))
        {
            this.ProcessStream(filestream);
        }
    }
    else
        throw new Exception(@"Couldn't read file from disk.");
}

public DImage(Stream stream) : this()   // Remove if no parameterless constructor
{
    this.ProcessStream(stream);
}    

public DImage(string strFileName) : this()  // Remove if no parameterless constructor
{
    // make sure the file exists
    if (System.IO.File.Exists(strFileName) == true)
    {
        this.strFileName = strFileName;

        // process stream from file
        this.ProcessStream(System.IO.File.Open(strFileName));
    }
    else
       throw new Exception(@"Couldn't find file '" + strFileName);
}

...

private ProcessStream(Stream myStream)
{
    if (filestream != null && filestream.Length > 0 && filestream.CanSeek == true)
    {
        //do stuff
    }
    else
        throw new Exception(@"Couldn't read file from disk.");
}

Upvotes: 4

Related Questions