协变类型参数可以在构造函数的输入位置吗?

Can a covariant type parameter be in an input position in the constructor?

, Michael 中建议将泛型类型参数设置为协变的,以允许创建空节点。

我知道通用类型参数在所有输出位置,因为 Tree<T> 及其子类型的所有属性都是只读的(val)。

但是它确实在构造函数的输入位置有类型参数。

我认为该代码在 C# 中不起作用,所以我尝试了一下,令我惊讶的是,它运行得很好。

// See this: 
// Short url: 
interface ITree<out T> { }

class Tree<T>: ITree<T> { }

sealed class Node<T> : Tree<T>
{
  private readonly T _left;
  private readonly T _right;

  public Node(T left, T right)
  {
    _left = left;
    _right = right;
   }

   public T Left { get { return _left; } }
   public T Right { get { return _right; } }
 }

class Program
{
  static void CovarianceTest1()
  {
     ITree<object> tree = new Node<string>("Hello", "World!");
  }
}

我现在意识到,在做这个练习时,我学到了一些关于方差的新知识。

所以,我的第一个问题是:

是否允许在构造函数的输入位置使用协变类型参数?在其他哪些地方允许类型参数忽略它们的方差限定符?

关于变体我了解到的另一件事是变体泛型类型参数甚至可能不会出现在变体接口声明中,如下例所示。

interface ITree<out T> { }

您会看到 ITree<out T> 接口在输入或输出位置都没有 T。这也让我很震惊。

我的第二个问题是:

我的另一个问题是,Kotlin 中 Nothing 类型的 C# 等价物是什么?答案说 Nothing 是最子类型,不能进一步推导出来。它与 Any(或其他语言中最基本的类型)完全相反。

要在 C# 中模拟该代码,没有意义:

class Empty : Tree<null> { }

因为那只是非法的 C# 代码,而且 null 似乎也不类似于 Nothing

所以,我不得不像这样伪造一个假人来模仿 Empty class 声明。

sealed class Dummy { }

sealed class Empty : Tree<Dummy>
{
  private static Empty _empty = null;
  private static object syncLock = new object();
  private Empty() { }
  public Empty Instance
  {
    get
    {
    if (_empty == null)
    {
      lock (syncLock)
      {
        if (_empty == null)
        {
          _empty = new Empty();
         }
        }
       }

       return _empty;
      }
   }
}

我的第三个也是最后一个问题是:

因此,我的最后一个问题是,是否有一个地方包含 Kotlin 中所有可用类型的详尽列表及其描述?因为即使Basic Types page lists most of the common ones, it seems not to be an exhaustive list. The types not listed there are all sprinkled over the documentation。就像上面的例子一样,它们只是出现在页面上的某个地方。

Kotlin 附带的所有类型都在其 API reference 中进行了描述,特别是 kotlin 包:

https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/