[英]Create an IEnumerable<SelectListItem> collection off a given type T in a generic class
[英]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)您有多种选择:
如果您希望集合存储任何IdText
( ManufacturedPart
或从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.