Slices in C#

using System;
using System.Collections.Generic;
using System.Linq;

class Slices
{
    static void Main()
    {
        // In C#, List<T> is commonly used as an equivalent to Go's slices.
        // An uninitialized List<T> is not null, but has Count 0.
        List<string> s = null;
        Console.WriteLine($"uninit: {s} {s == null} {s?.Count == 0}");

        // To create an empty list with non-zero capacity, we can use the constructor.
        s = new List<string>(3);
        Console.WriteLine($"emp: [{string.Join(" ", s)}] len: {s.Count} cap: {s.Capacity}");

        // We can add elements to the list.
        s.Add("a");
        s.Add("b");
        s.Add("c");
        Console.WriteLine($"set: [{string.Join(" ", s)}]");
        Console.WriteLine($"get: {s[2]}");

        // Count returns the length of the list as expected.
        Console.WriteLine($"len: {s.Count}");

        // We can add more elements to the list.
        s.Add("d");
        s.AddRange(new[] { "e", "f" });
        Console.WriteLine($"apd: [{string.Join(" ", s)}]");

        // Lists can be copied.
        List<string> c = new List<string>(s);
        Console.WriteLine($"cpy: [{string.Join(" ", c)}]");

        // We can use Range to get a portion of the list.
        List<string> l = s.GetRange(2, 3);
        Console.WriteLine($"sl1: [{string.Join(" ", l)}]");

        // This gets elements up to (but excluding) index 5.
        l = s.GetRange(0, 5);
        Console.WriteLine($"sl2: [{string.Join(" ", l)}]");

        // And this gets elements from index 2 to the end.
        l = s.GetRange(2, s.Count - 2);
        Console.WriteLine($"sl3: [{string.Join(" ", l)}]");

        // We can declare and initialize a list in a single line.
        List<string> t = new List<string> { "g", "h", "i" };
        Console.WriteLine($"dcl: [{string.Join(" ", t)}]");

        // C# provides methods for comparing lists.
        List<string> t2 = new List<string> { "g", "h", "i" };
        if (t.SequenceEqual(t2))
        {
            Console.WriteLine("t == t2");
        }

        // Lists can be composed into multi-dimensional data structures.
        List<List<int>> twoD = new List<List<int>>();
        for (int i = 0; i < 3; i++)
        {
            twoD.Add(new List<int>());
            for (int j = 0; j <= i; j++)
            {
                twoD[i].Add(i + j);
            }
        }
        Console.WriteLine($"2d: {string.Join(", ", twoD.Select(row => $"[{string.Join(" ", row)}]"))}");
    }
}

This C# code demonstrates concepts similar to Go’s slices using List<T>. Here are some key points:

  1. C# uses List<T> as a dynamic array, which is similar to Go’s slices.
  2. Unlike Go slices, an uninitialized List<T> in C# is not null by default, but has a count of 0.
  3. C# uses Add and AddRange methods to append elements, similar to Go’s append.
  4. C# provides GetRange method to slice a list, which is similar to Go’s slice operator.
  5. C# uses collection initializers to create and initialize a list in one line.
  6. The SequenceEqual method in C# is used to compare two lists, similar to the slices.Equal function in Go.
  7. Multi-dimensional lists in C# can have varying inner list lengths, just like in Go.

When you run this program, you’ll see output similar to the Go example, demonstrating the various operations on lists in C#.

Note that while C#’s List<T> is similar to Go’s slices in many ways, there are some differences in behavior and performance characteristics. C# also provides other collections like Array, ArrayList, and IList<T> which might be more appropriate in certain scenarios.