Is it possible to use the type of 'this' in a generic as a constraint itself?

Viewed 70

Consider this made-up example...

public abstract class CollectionItem<TSelf> {

    protected CollectionItem(ICollection<TSelf> siblings)
        => Siblings = siblings;

    public ICollection<TSelf> Siblings { get; }
}

public class Foo : CollectionItem<Foo>{

    public Foo()
    : base(new FooCollection){}
}

public class FooCollection : ObservableCollection<Foo>{
}

With the above, Foo now has a Siblings property. However, there are three problems with this.

  1. I have to repeat the redundant Foo in the generic
  2. Siblings itself isn't typed to the actual collection type, but rather the interface.
  3. I have to actually pass in an instance of the Siblings collection

Solving for #2 and #3, I made this change...

public class CollectionItem<TSelf, TSiblings>
where TSiblings : ICollection<TSelf>, new() {

    protected CollectionItem()
        => Siblings = new TSiblings();

    public TSiblings Siblings { get; }
}

but I still have to pass in the seemingly redundant Foo as the first type parameter, like this...

public class Foo : CollectionItem<Foo, FooCollection>{

}

In Swift, you have an implicit Self datatype which always represents the type of the current instance, meaning if Self is used in a base class, it's actually a stand-in for the data type of the subclass. Think of it as an implicit generic if you will.

Having that in C# would allow me to do something like this...

public class CollectionItem<TSiblings>
where TSiblings : ICollection<Self>, new() { // Note it uses 'Self' here

    protected CollectionItem()
        => Siblings = new TSiblings();

    public TSiblings Siblings { get; }
}

public class Foo : CollectionItem<FooCollection>{

}

public class Laa : CollectionItem<LaaCollection>{

}

In the above, for instances of Foo, Self refers to Foo. For instances of Laa, Self refers to Laa. No need to pass the redundant type parameters.

So does C# have anything similar?

0 Answers
Related