C# Different way to join string array
Published: 2023-09-03 18:11:11

Learn how to create a comma delimited string that goes past using [String.Join method](https://learn.microsoft.com/en-us/dotnet/api/system.string.join?view=net-7.0).

## Code blocks

Rather than use separate methods, all code is presented in the main method of a Console project.

```csharp
{
  code
}
```

Where **code** is isolated from all other code.

Note, **index = 1;** in this case is out of scope from the assignment.

```csharp
{
    {
        int index = 0;
    }

    index = 1;
}
```

## Convention method to join 

Using String.Join to create a comma delimited string of month names which once joined as a string there is no easy method to modify data e.g. add/remove, in this case a month name.

```csharp
Console.WriteLine(string.Join(",", 
    DateTimeFormatInfo.CurrentInfo.MonthNames[..^1]));
```

## CommaDelimitedStringCollection

 [CommaDelimitedStringCollection](https://learn.microsoft.com/en-us/dotnet/api/system.configuration.commadelimitedstringcollection?view=dotnet-plat-ext-7.0) class provides methods and properties to add, edit, test if values exists, iterate with a for statement and much more.

:stop_sign: Downside and one may guess as the name implies, the delimiter can not be changed from a comma. 

Create an instance of CommaDelimitedStringCollection and add month names.

```csharp
CommaDelimitedStringCollection result = new();
result.AddRange(DateTimeFormatInfo.CurrentInfo.MonthNames[..^1]);
```
Display the results

```csharp
Console.WriteLine($"\t{result}");
```

Remove the current month.

```csharp
var currentMonthName = 
    DateTime.Now.ToString("MMMM", CultureInfo.InvariantCulture);
result.Remove(currentMonthName);
```

Insert the current month back in.

```csharp
result.Insert(DateTime.Now.Month -1, currentMonthName);
```
What is cool is iterating the collection, in this case month name.

```csharp
for (var index = 0; index < result.Count; index++)
{
    Console.WriteLine($"{index +1, -3}{result[index]}");
}
```

Results

```
1  January
2  February
3  March
4  April
5  May
6  June
7  July
8  August
9  September
10 October
11 November
12 December
```

## Useful for debugging

Example, a developer is testing the following method to find files.

```csharp
static class FileHelpers
{
    /// <summary>
    /// Find files with no regard to if the user has permissions
    /// </summary>
    /// <param name="path">Folder name to check</param>
    /// <param name="extensions">file extensions</param>
    /// <returns></returns>
    public static string[] FilterFiles(string path, params string[] extensions)
        => extensions
            .Select(filter => $"*.{filter}")
            .SelectMany(item =>
                Directory.EnumerateFiles(
                    path,
                    item,
                    SearchOption.AllDirectories)).ToArray();
}
```

Rather than using StringBuilder the developer can use CommaDelimitedStringCollection.

```csharp
{
    AnsiConsole.MarkupLine("[yellow]Files found[/]");
    CommaDelimitedStringCollection result = new();
    var files = FileHelpers.FilterFiles(Path.Combine(AppDomain.CurrentDomain.BaseDirectory),"txt","json");
    foreach (var file in files)
    {
        result.Add(Path.GetFileName(file));
    }
    Console.WriteLine($"\t{result}");
    Console.WriteLine(result.Contains("appsettings.json").ToYesNo());
}
```






## Using numerics

As the name implies CommaDelimited**StringCollection** there are no overloads for other types but we can simply do a conversion.

For int array, use the following language extension.

```csharp
static class Extensions
{
    /// <summary>
    /// int array to string array
    /// </summary>
    /// <param name="sender"></param>
    public static string[] ToStringArray(this int[] sender)
        => sender.Select(x => x.ToString()).ToArray();
}
```
Usage

```csharp
int[] items = { 1, 2, 3 };
CommaDelimitedStringCollection result = new();
result.AddRange(items.ToStringArray());
```

Check if 3 is in the collection.

```csharp
result.Contains("3")
```

## Set to read only

For when the collection should not be modified, use [SetReadOnly](https://learn.microsoft.com/en-us/dotnet/api/system.configuration.commadelimitedstringcollection.setreadonly?view=dotnet-plat-ext-7.0)() method.

```csharp
{
    AnsiConsole.MarkupLine("[yellow]Files found[/]");
    CommaDelimitedStringCollection result = new();
    var files = FileHelpers.FilterFiles(Path.Combine(AppDomain.CurrentDomain.BaseDirectory), "txt", "json");
    foreach (var file in files)
    {
        result.Add(Path.GetFileName(file));
    }
    Console.WriteLine($"\t{result}");
    Console.WriteLine(result.Contains("appsettings.json").ToYesNo());

    result.SetReadOnly();
    try
    {
        result.Add("SomeFile.txt");
    }
    catch (Exception e)
    {
        Console.WriteLine(e);

    }
}
```

Rather than try/catch

```csharp
result.SetReadOnly();
if (!result.IsReadOnly)
{
    result.Add("SomeFile.txt");
}
```

![screenshot of code samples](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/95ey478xfe7wnezieff9.png)

## Clear the collection

See the [Clear](https://learn.microsoft.com/en-us/dotnet/api/system.configuration.commadelimitedstringcollection.clear?view=dotnet-plat-ext-7.0) method.

## Clone the collection

See the [Clone](https://learn.microsoft.com/en-us/dotnet/api/system.configuration.commadelimitedstringcollection.clone?view=dotnet-plat-ext-7.0) method


## NuGet packages required

:small_orange_diamond: [System.Configuration.ConfigurationManager](https://www.nuget.org/packages/System.Configuration.ConfigurationManager/6.0.1?_src=template) 

## Source code

Can be found [here](https://github.com/karenpayneoregon/closet-code/tree/master/CommaDelimitedStringCollectionSampleApp) which is in a GitHub repository with a mix of other code samples.