1

I'm Writing to 2 files at a time from a row in a csv, basically I have a list of rows that some have errors so I want to create a log file with detailed errors per row and a new csv with all these rows that had errors, so I'm opening 2 streamwriters at a time, so instead of doing a using block within a using block im doing

using (var writer = new StreamWriter[] { new StreamWriter(infoFolderPath + "/Import Errors.txt"), new StreamWriter(infoFolderPath + "/Failed Import Rows.csv") })
{
    foreach (var err in rowsWithErrors)
    {
        writer[0].WriteLine(Write row error here...);
        writer[1].WriteLine(Write row in csv here...);
    }
}

But the problem with this is I get an error 'StreamWriter[]': type used in a using statement must be implicitly convertible to 'System.IDisposable'. I understand that I need to be able to dispose of the Stream after its done and the using block cant find the Dispose method because its an array of type stream and not of type stream.

So my question is, is there a way to make this work or a smarter way to write to a few files?

(please don't answer to make 2 using statements because I'm writing to more then 2 files I just simplified for the question to be easy to understand...)

big boy
  • 315
  • 2
  • 13
  • Is the number of files unbounded? – Robert Harvey Aug 30 '22 at 12:27
  • @RobertHarvey it is bounded – big boy Aug 30 '22 at 12:28
  • What is the maximum number of files? – Robert Harvey Aug 30 '22 at 12:29
  • @RobertHarvey always 4 files – big boy Aug 30 '22 at 12:31
  • If the number is always 4, I would just declare 4 variables with explicit names. Don't use an array with cryptic references like `writer[1]`. The `using` statements can be simplified through either `using var writer = ...` (`using` declarations) or by old-school stacking of the statements without using separate blocks (`using (var ..) using (var ...) using (var ..) { ... }`). – Jeroen Mostert Aug 30 '22 at 12:32
  • @bigboy - if it is only 4 you can just stack the `using` statements. VS (and other IDEs) dont have to have nesting when you stack statements. Is that the issue (too much indentation) or is there another reason to not do it? – Igor Aug 30 '22 at 12:32
  • @Igor the issue is too much indentation and too messy code (which I HATE!) – big boy Aug 30 '22 at 12:33
  • 1
    `using` statements can be stacked, without the need of additional braces. See https://stackoverflow.com/a/1329765/102937 – Robert Harvey Aug 30 '22 at 12:35
  • 1
    Also consider that you may also just be trying to do too much in a single method, if it's a complex operation with a lot of state. If those writers were fields of an object, you could dispose of them in the `Dispose` of that object, and creating them would also be separate from your core logic. – Jeroen Mostert Aug 30 '22 at 12:39

1 Answers1

3

Change it to a try/finally block instead which is what using equates to.

var writer = new StreamWriter[] { new StreamWriter(infoFolderPath + "/Import Errors.txt"), new StreamWriter(infoFolderPath + "/Failed Import Rows.csv") }
try
{
    foreach (var err in rowsWithErrors)
    {
        writer[0].WriteLine(Write row error here...);
        writer[1].WriteLine(Write row in csv here...);
    }
}
finally
{
    foreach(var w in writer)
    {
      w.Dispose();
    }
}

Based on the comments it is always 4 streams. I would personally just stack the using statements (or var if using a supported c# version). Notice that there is no additional indentation for each additional using statement. This also allows you to give meaningful names to your variables (unlike my code example below).

using (var writer1 = new StreamWriter(infoFolderPath + "/Import Errors.txt"))
using (var writer2 = new StreamWriter(infoFolderPath + "/Failed Import Rows.csv"))
using (var writer3 = new StreamWriter(infoFolderPath + "/other.txt"))
using (var writer4 = new StreamWriter(infoFolderPath + "/other2.txt"))
{
    foreach (var err in rowsWithErrors)
    {
        writer1.WriteLine(Write row error here...);
        writer2.WriteLine(Write row in csv here...);
        writer3.WriteLine(Write row error here...);
        writer4.WriteLine(Write row in csv here...);
    }
}

If you are using c# 8 or higher you can reduce the nesting even more with var using.

using var writer1 = new StreamWriter(infoFolderPath + "/Import Errors.txt");
using var writer2 = new StreamWriter(infoFolderPath + "/Failed Import Rows.csv");
using var writer3 = new StreamWriter(infoFolderPath + "/other.txt");
using var writer4 = new StreamWriter(infoFolderPath + "/other2.txt");

foreach (var err in rowsWithErrors)
{
    writer1.WriteLine(Write row error here...);
    writer2.WriteLine(Write row in csv here...);
    writer3.WriteLine(Write row error here...);
    writer4.WriteLine(Write row in csv here...);
}
Igor
  • 60,821
  • 10
  • 100
  • 175
  • 1
    What if one of those throw in their dispose call – Daniel A. White Aug 30 '22 at 12:29
  • thx, that is a smart solution, if no-one comes up with something better I'll accept it as the answer – big boy Aug 30 '22 at 12:29
  • 2
    @DanielA.White - According to MS best practices Dispose should always swallow any Exceptions thrown *but* yes, that could happen although I am not sure specifically about the implementation of `StreamWriter` if it does this or not. You would have to wrap the `Dispose` in a `try/catch` in the loop. – Igor Aug 30 '22 at 12:30
  • 1
    ah, didn't know you can stack them... both good answers, thx a million – big boy Aug 30 '22 at 12:37
  • 1
    I second the stacked using recommendation, also consider [using var declaration](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement), i.e. `using var writer1 = ...` – JonasH Aug 30 '22 at 12:37
  • 1
    the project I'm working on is still C# version 7.3 and this feature is from C# v8.0 and greater... – big boy Aug 30 '22 at 12:41
  • @BigBoy You can [select version](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/configure-language-version) in the project file. This might not be supported, but I have yet to encounter any major issues using the latest c# version with .Net 4.8. – JonasH Aug 30 '22 at 12:48