簡體   English   中英

為什么我不能通過List <T> 一般的構造函數參數雖然滿足所有約束?

[英]Why can't I pass List<T> to a generic constructor parameter although all contraints are met?

我有以下代碼:

public class SampleClass<T, TCollection> where TCollection : class, IList<T>, IReadOnlyList<T>
{
    private readonly TCollection _collection;

    public SampleClass() : this(new List<T>()) { }

    public SampleClass(TCollection collection)
    {
        _collection = collection;
    }
}

不幸的是,包含默認構造函數public SampleClass() : this(new List<T>()) { }無法編譯。 錯誤消息說: 參數1:無法從'System.Collections.Generic.List'轉換為'TCollection'

為什么會這樣? List<T>實際上符合我放置在TCollection泛型上的所有約束:它是一個實現IList<T>IReadOnlyList<T>

非常感謝你的幫助。

編輯:更新了代碼,因為它包含錯誤。

為什么會這樣?

問題是我可以寫這樣的代碼:

class X : IList<int>, IReadOnlyList<int>
{
    ...
}

然后嘗試使用它:

var instance = new SampleClass<int, X>();

但是沒有從List<int>X轉換。

此方案的可能性是您收到編譯器錯誤消息的原因:

參數1:無法從'System.Collections.Generic.List'轉換為'TCollection'。

要獲得您正在尋找的“ List<T>默認”行為,您可以擺脫該默認構造函數並將其替換為以下內容:

static class SampleClass
{
    public static SampleClass<T, List<T>> Create<T>()
    {
        return new SampleClass<T, List<T>>(new List<T>());
    }
}

這是一個類似於Tuple靜態類的模式,其靜態Tuple.Create泛型方法和非靜態Tuple<T1>Tuple<T1, T2>等類。

您的方法的問題是您假設您可以將List<T>分配給類型為TCollection的引用,而實際上並不知道TCollection是什么。 您可以在這里使用兩種方法。 前者更接近你現在擁有的,而后者允許你編寫一個更容易在更廣泛的場景中使用的類。

  1. TCollection使用new約束。 雖然你仍然不知道TCollection的類型,編譯器要求類型有一個默認的構造函數,允許你寫這個:

     public class SampleClass<T, TCollection> where TCollection : IList<T>, IReadOnlyList<T>, new() { public SampleClass() : this(new TCollection()) { } public SampleClass(TCollection collection) { ... } } 
  2. 要求在TCollection的實例中調用代碼傳遞,而不是自己創建它。 在這種情況下,您只需刪除默認構造函數。

將泛型約束更改為TCollection並添加new()約束。 然后,您可以使用new TCollection()初始化類

public class SampleClass<T, TCollection> where TCollection : class, IList<T>, IReadOnlyList<T>, new()
{
    private readonly TCollection _collection;

    public SampleClass() : this(new TCollection()) { }

    public SampleClass(TCollection collection)
    {
        _collection = collection;
    }
}

我相信Sam Harwell有部分答案,你真的希望TCollection是包含T元素的東西,所以你應該有:

public class SampleClass<T, TCollection>
  where TCollection : class, IList<T>, IReadOnlyList<T>

但是,這還不足以處理這樣一個事實,即您希望有一個無參數構造函數將new List<T>()傳遞給采用TCollection參數的構造函數。 某些東西可能是一個TCollection而不是List<T>或它的基礎,因此沒有足夠的約束來保證這將起作用。

有三種可能的方法。 一,完全擺脫無參數構造函數:

public class SampleClass<T, TCollection> where TCollection : class, IList<T>, IReadOnlyList<T>, new()
{
  private readonly TCollection _collection;

  public SampleClass(TCollection collection)
  {
    _collection = collection;
  }
}

二,將傳入的集合存儲為List<T>並堅持認為TCollection要么是它,要么是從它派生的(不太可能有用):

public class SampleClass<T, TCollection> where TCollection : List<T>
{
  private readonly List<T> _collection;

  public SampleClass() : this(new List<T>()) { }

  public SampleClass(TCollection collection)
  {
    _collection = collection;
  }
}

三,堅持認為TCollection是一個帶無參數構造函數的類,並使用:

public class SampleClass<T, TCollection> where TCollection : class, IList<T>, IReadOnlyList<T>, new()
{
  private readonly TCollection _collection;

  public SampleClass() : this(new TCollection()) { }

  public SampleClass(TCollection collection)
  {
    _collection = collection;
  }
}

TCollection是你定義的一個類?

List<T>實現:

public class List<T> : IList<T>, ICollection<T>, IList, ICollection, IReadOnlyList<T>,
       IReadOnlyCollection<T>, IEnumerable<T>, IEnumerable

TCollection是否實現IListICollection或繼承List<T>Collection<T>的基類? 您的TCollection必須實現或繼承其中一個以刪除編譯錯誤。

您還需要將類TCollection更改為TCollection<T> ,以便接受通常定義的new List<T> 通用需要在某處傳遞給您的集合。

當然,除非你將約束放在定義TCollection上。 您可能需要注意的是,您對通用<T>而不是TCollection設置了約束。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM