1

I have IBinaryNode interface and IRedBlackNode interface that inherits from IBinaryNode.

public interface IBinaryNode<T>
{
    public IBinaryNode<T>? Left  { get; set; }
    public IBinaryNode<T>? Right { get; set; }
    public T              Value { get; }

}

public interface IRedBlackNode<T> : IBinaryNode<T>
{
    IRedBlackNode<T>? Parent  { get; set; }
    bool              IsBlack { get; set; }
}

How can I use IRedBlackNode instead of IBinaryNode in the properties of the following class? I thought that if IRedBlackNode implements IBinaryNode then I can do it but I get type error that says that it must be IBinaryNode instead.

private class RedBlackNode : IRedBlackNode<T>
{
    public IRedBlackNode<T>? Parent  { get; set; }
    public IRedBlackNode<T>? Left    { get; set; }
    public IRedBlackNode<T>? Right   { get; set; }
    public bool              IsBlack { get; set; }
    public T                 Value   { get; }
}
  • If you are looking for solution (and not explanation) search for "curiously recurring template in C#". For explanation read classical https://stackoverflow.com/questions/16966961/cannot-convert-from-listderivedclass-to-listbaseclass and it may be enough... or continue reading on (co-)variance and [LSP](https://en.wikipedia.org/wiki/Liskov_substitution_principle). – Alexei Levenkov Sep 16 '22 at 19:27
  • [Covariant return types](https://github.com/dotnet/csharplang/issues/49) may come in some future version of C# – Haukinger Sep 16 '22 at 20:18

2 Answers2

1

Actually, you can't. Consider you have an instance of RedBlackNode, then it can be cast to IBinaryNode<T> and any other IBinaryNode<T> can be assigned to its Right property.

But, if you want to restrict class RedBlackNode to have only instances of IRedBlackNode<T> in its Right property, you can do it via explicit interface implementation:

public IRedBlackNode<T> Right { get; set; }

IBinaryNode<T> IBinaryNode<T>.Right
{
  get => Right;
  set => Right = (IRedBlackNode<T>)value;
}

P.S. If you only have getters on Left and Right it will work through covariance, but you have also setters

Quercus
  • 2,015
  • 1
  • 12
  • 18
1

I guess it will still work. Here's an example on how you could implement that. But further I don't see any problems here.

public interface IBinaryNode<T>
    where T : class
{
    public IBinaryNode<T>? Left { get; set; }
    public IBinaryNode<T>? Right { get; set; }
    public T Value { get; }

}

public interface IRedBlackNode<T> : IBinaryNode<T>
    where T : class
{
    IRedBlackNode<T>? Parent { get; set; }
    bool IsBlack { get; set; }
}

public class RedBlackNode<T> : IRedBlackNode<T>
    where T: class
{
    public IRedBlackNode<T>? Parent { get; set;}
    public IBinaryNode<T>? Right { get; set }
    public IBinaryNode<T>? Left { get; set ; }
    public bool IsBlack { get; set; }
    public T Value { get; }
}   
Paul Sinnema
  • 2,534
  • 2
  • 20
  • 33