Reputation: 55534
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
Reputation: 11596
I could imagine implementing 3 constructors:
System.Stream
that can be accessed by a System.IO.StreamReader
System.IO.MemoryStream
and calling the first constructor.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:
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
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
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