簡體   English   中英

使用IEnumerable創建通用集合的通用類<T>

[英]Generic Class to create a Generic Collection using IEnumerable<T>

這是關於泛型兩(2)部分問題

我必須創建幾個類似的類來對設計類似的數據庫表進行建模。

所有表都包含一個ID int和一個Text nvarchar(50)字段。 一兩個可能包含其他幾個字段。

我很少使用泛型 ,但是我經常在這里看到其示例。 這是我創建另一個通用類中使用的通用類的最大嘗試。

我的基本構造如下,我將在注釋中指出什么是行不通的,並顯示Visual Studio 2010的錯誤消息:

public class IdText {

  public IdText(int id, string text) {
    ID = id;
    Text = text;
  }

  public int ID { get; private set; }

  public string Text { get; private set; }

}

public class TCollection<T> : IEnumerable<T> where T : IdText {

  private List<T> list;

  public TCollection() {
    list = new List<T>();
  }

  public void Add(int id, string text) {
    foreach (var item in list) {
      if (item.ID == id) {
        return;
      }
    }
    list.Add(new T(id, text)); // STOP HERE
    // Cannot create an instance of the variable type 'T'
    // because it does not have the new() constraint
  }

  public T this[int index] {
    get {
      if ((-1 < 0) && (index < list.Count)) {
        return list[index];
      }
      return null;
    }
  }

  public T Pull(int id) {
    foreach (var item in list) {
      if (item.ID == id) {
        return item;
      }
    }
    return null;
  }

  public T Pull(string status) {
    foreach (var item in list) {
      if (item.Text == status) {
        return item;
      }
    }
    return null;
  }

  #region IEnumerable<T> Members

  public IEnumerator<T> GetEnumerator() {
    foreach (var item in list) yield return item;
  }

  #endregion

  #region IEnumerable Members

  System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
    return list.GetEnumerator();
  }

  #endregion

}

Visual Studio的IntelliSence要我添加list.Add(T item) ,但是我需要先創建它。

我試圖重寫有問題的線路list.Add(new T(id, text)); 作為list.Add(new IdText(id, text)); ,但隨后出現消息“無法從IdText轉換為T

我該如何解決呢?

下一步:當我稍后實際創建此IdText類的版本時,我不確定如何在為它設計的TCollection類中使用該新類。

例如,給定此派生類:

public class ManufacturedPart : IdText {

  public ManufacturedPart(int id, string partNum, string description)
    : base(int id, string partNum) {
    Description = description;
  }

  public string Description { get; private set; }

}

...我是否還需要派生一個特殊版本的TCollection來像它一樣?

public class ManufacturedParts<T> : IEnumerable<T> where T : ManufacturedPart {

  // OK, now I'm lost! Surely this can't be right!

}

1)您可以使用new()約束,將屬性公開,並添加一個無參數的構造函數:

public class IdText
{
    public IdText()
    {
    }

    public IdText(int id, string text)
    {
        ID = id;
        Text = text;
    }

    public int ID { get; set; }

    public string Text { get; set; }

}

public class TCollection<T> : IEnumerable<T> where T : IdText, new()
{

    private List<T> list;

    public TCollection()
    {
        list = new List<T>();
    }

    public void Add(int id, string text)
    {
        foreach (var item in list)
        {
            if (item.ID == id)
            {
                return;
            }
        }
        list.Add(new T { ID = id, Text = text }); 
    }
}

2)您有多種選擇:

如果您希望集合存儲任何IdTextManufacturedPart或從IdText派生的其他任何內容):

TCollection<IdText> ss = new TCollection<IdText>();

到目前為止,以上內容只能在實例化Add(int, string)方法中的對象時存儲IdText ,但是如果提供Add(T object)方法,則可以存儲任何IdText實例。

如果您希望集合僅包含ManufacturedParts

public class ManufacturedParts<T> : TCollection<T> where T : ManufacturedPart, new()
{
     // Provide here some specific implementation related to ManufacturedParts
     // if you want. For example, a TotalPrice property if ManufacturedPart
     // has a Price property.
}

TCollection<ManufacturedPart> ss2 = new ManufacturedParts<ManufacturedPart>();

甚至更簡單(如果您的集合沒有根據存儲對象的類型提供任何其他方法):

TCollection<ManufacturedPart> ss2 = new TCollection<ManufacturedPart>();

更簡單的是,如果您的目標是僅存儲對象,則不需要自定義集合:

List<IdText> ss2 = new List<IdText>();  // Uses the built-in generic List<T> type

關於第一個問題:c#不支持帶有參數作為通用約束的構造函數。 您可以將其替換為

(T)Activator.CreateInstance(typeof(T),new object[]{id,text});

另一方面,您實際上並不知道派生類的構造函數的外觀,因此無法確保它們具有該構造函數。

關於第二個問題,您可以這樣做:

var collection = new TCollection<ManufacturedPart>();

列表的工作方式相同。

希望能幫助到你。

如果您的集合類將負責實例化其集合類型的元素,則您可能不希望使用new()約束或Activator.CreateInstance() ,就像Jon Skeet所寫的那樣 ,這兩種方法均表現不佳。性能。

聽起來您真正想要的是提供者委托,如下所示:

public class MyCollection<T> : IEnumerable<T> where T : IdText {
    private readonly List<T> list;
    private readonly Func<int, string, T> provider;

    public MyCollection(Func<int, string, T> provider) {
        this.list = new List<T>();
        this.provider = provider;
    }

    public void Add(int id, string text) {
        list.Add(provider(id, text));
    }
}

然后你會像以下一樣使用它:

var collection = new MyCollection((id, text) => new ManufacturedPart(id, text));

您可以認為這是將要用作參數的特定構造函數傳遞給類,然后根據需要使用該構造函數構造實例。

而且您不需要為MyCollection<ManufacturedPart>創建單獨的子類-只需直接使用泛型類即可。

暫無
暫無

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

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