简体   繁体   中英

C# streaming to XML or html or other future outputs

I have a simple class XMLSTream that allows me to pass data from an application to an XML document that opens in Word.

I have a simple class HTMLStream that allows me to pass data from an application to a HTML document that opens in Internet Explorer.

Both of my stream classes work perfectly individually.

I have aligned these classes to matching structures, in the hope that the users selection from a file dialog box will determine which 'Stream Class' is used. What I cannot figure out, is how to use the same code in the calling class regardless of the type.

myHtmlStream
{
protected Stream myStream;
protected StreamWriter myWriter;
Open() {// block of code};
Close() {// block of code} ;
WriteLine (string myLine) { // block of code} ; 
// etc;  
}

myXMLStream
{
protected Stream myStream;
protected StreamWriter myWriter;
Open() {// block of code};
Close() {// block of code} ;
WriteLine (string myLine) { // block of code} ; 
// etc;  
}

calling class does the following:

SaveFileDialog sDlg = new SaveFileDialog();
sDlg.Filter = "htm files (*.htm)|*.htm|xml files (*.xml)|*.xml";
sDlg.FilterIndex = 1;
if (sDlg.ShowDialog() == DialogResult.OK)
{
    if (sDlg.FilterIndex == 1)
    {
        myHtmlStream mH = new myHtmlStream();
        mH.Open();
        mH.WriteLine("This is a HTML document");
        mH.Close();
    }
    else if (sDlg.FilterIndex == 2)
    {
        myXMLStreammX mX= new myXMLStream();
        mX.Open();
        mX.WriteLine("This is an XML document");
        mX.Close();
    }

}

You can see the same steps are called regardless of the selected file type, but it is nasty to add components to the report, as they have to be entered twice. (I also have methods that create tables, populate cells, etc for complicated reports.).

With inheritance I should be able to simplify this, anyone have a link to anything that might help assist? In the actual code, its way more than 4 lines of XML/HTML output for the actual data. I know in theory at least there is an elegant way to handle this

In my opinion, the best solution here is to define an interface and an abstract class.

Define something along the lines of this:

public interface IOutputStream
{
    void Open();
    void Close();
    void WriteLine(string line);
}

public abstract class OutputStreamBase : IOutputStream
{
    // create cross-cutting concerns here, logging, file handling, etc.
    // create virtual methods and properties that are common to all descendants
    public virtual void Open()
    {
        throw new System.NotImplementedException();
    }

    public virtual void Close()
    {
        throw new System.NotImplementedException();
    }

    public virtual void WriteLine(string line)
    {
        throw new System.NotImplementedException();
    }

    protected virtual void DoSomething()
    {
    }

    protected abstract void DoSomethingElse();
}

Then, once you have these, you can define as many concrete implementations as you need:

public class HtmlStream : OutputStreamBase
{
    protected override void DoSomethingElse()
    {
        throw new System.NotImplementedException();
    }
}

public class XmlStream : OutputStreamBase
{
    protected override void DoSomethingElse()
    {
        throw new System.NotImplementedException();
    }
}

Then, in your calling code, create a variable of type IOutputStream and assign it as needed:

    public void Test()
    {
        IOutputStream outputStream;

        if (sDlg.ShowDialog() == DialogResult.OK)
        {
            if (sDlg.FilterIndex == 1)
                outputStream = new HtmlStream();
            else if (sDlg.FilterIndex == 2)
                outputStream = new XmlStream();
            else
                throw new InvalidOperationException();
        }

        outputStream.Open();
        outputStream.WriteLine("ContentHere");
        outputStream.Close();
    }
}

Then, you can use the same method calls regardless of implementation.

Since you are dealing with resources such as files, streams, etc. it might also be prudent to implement the IDisposable interface too, and wrap the whole thing up in a (using var stream = ... ) block to ensure your resources get flushed, closed and disposed of when finished.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM