Declaring a variable of self-referencing generic type in C# 10.0

45 views Asked by At

Good time of the day!

I have a generic interface which has a self-reference:

public interface IBuilder<TObject, TBuilder>
    where TBuilder : IBuilder<TObject, TBuilder>
{
    public TObject Build();
}

so I can use it like this:

public abstract class Builder<TObject, TBuilder> : IBuilder<TObject, TBuilder>
    where TBuilder : Builder<TObject, TBuilder>
{
    protected TObject obj;
    protected readonly TBuilder @this;
    protected abstract TObject CreateObject();
    protected abstract void CheckBuildConstraints();

    public Builder()
    {
        obj = CreateObject();
        @this = (TBuilder)this;
    }

    public virtual TObject Build()
    {
        CheckBuildConstraints();
        return obj;
    }
}
public interface IContext
{
    string Name { get; }
}
public interface IContextBuilder<TContext, TBuilder> : IBuilder<TContext, TBuilder>
    where TContext : IContext
    where TBuilder : IContextBuilder<TContext, TBuilder>
{
    //...

    TBuilder SetName(string name);
}
public class Context : IContext
{
    public string Name => _name!;

    protected string? _name;

    protected Context() { }

    public abstract class ContextBuilder<TContext, TBuilder>
        : Builder<TContext, TBuilder>, IContextBuilder<TContext, TBuilder>
        where TContext: Context
        where TBuilder : ContextBuilder<TContext, TBuilder>
    {
        public ContextBuilder() : base() { }

        protected override void CheckBuildConstraints()
        {
            obj._name ??= "default value";
        }

        //...

        public TBuilder SetName(string name)
        {
            obj._name = name;
            return @this;
        }
    }

    public class ContextBuilder : ContextBuilder<Context, ContextBuilder>
    {
        public ContextBuilder() : base() { }

        protected override Context CreateObject() => new();
    }
}

and then do these FluentAPI-style chained calls:

var context = new Context.ContextBuilder().SetName("name").Build();

My questions are these:

  1. Do I overcomplicate things? Is there any simpler way to do what I did?
  2. How do I declare a variable of IContextBuilder<IContext, IContextBuilder<...>> type?

I have googled a lot of information and I have not been able to find anything usefull so far. I am hoping for your help. Cheers!

0

There are 0 answers