Struct Embedding in C#

C# supports composition of types through inheritance and interfaces. While it doesn’t have a direct equivalent to Go’s struct embedding, we can achieve similar functionality using inheritance and interfaces.

using System;

// Base class
public class Base
{
    public int Num { get; set; }

    public string Describe()
    {
        return $"base with num={Num}";
    }
}

// Container class inherits from Base
public class Container : Base
{
    public string Str { get; set; }
}

// Interface for describing
public interface IDescriber
{
    string Describe();
}

class Program
{
    static void Main()
    {
        // Creating an instance of Container
        var co = new Container
        {
            Num = 1,
            Str = "some name"
        };

        // We can access the base's fields directly on co
        Console.WriteLine($"co={{num: {co.Num}, str: {co.Str}}}");

        // We can also access the base's fields using the base keyword
        Console.WriteLine($"also num: {co.Num}");

        // Since Container inherits from Base, it has access to Base's methods
        Console.WriteLine($"describe: {co.Describe()}");

        // Container implements IDescriber interface implicitly through inheritance
        IDescriber d = co;
        Console.WriteLine($"describer: {d.Describe()}");
    }
}

When you run this program, you’ll see the following output:

co={num: 1, str: some name}
also num: 1
describe: base with num=1
describer: base with num=1

In C#, we use inheritance to achieve a similar effect to Go’s struct embedding. The Container class inherits from the Base class, which allows it to access all public members of Base.

We define an IDescriber interface that declares the Describe method. Since Base implements this method and Container inherits from Base, Container automatically implements the IDescriber interface.

This example demonstrates how C# uses inheritance and interfaces to create a composition of types, allowing for code reuse and polymorphism. While the syntax and exact mechanisms differ from Go’s struct embedding, the end result is similar in terms of functionality and code organization.