美好的一天。泛型通常使用如下:
class MyList<T>
{
public T data;
public MyList<T> nextElement;
}
为什么不使用follow:
class MyList
{
public object data;
public MyList nextElement;
}
甚至:
class MyStructure<T> where T : SomeCommonClass
{
public T data;
public MyStructure<T> nextElement;
public MyStructure<T> prevElement;
}
而是:
class MyStructure
{
public SomeCommonClass data;
public MyStructure nextElement;
public MyStructure prevElement;
}
更新
好吧,我担心你没有完全理解我,甚至降低了我的问题。没有泛型的示例,它可以正常工作:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
MyNode nodeButton = new MyNode("nodeButton", new Button());
MyNode nodeTextBox = new MyNode("nodeTextBox", new TextBox());
MyNode nodeCheckBox = new MyNode("nodeCheckBox", new CheckBox());
MyList myList = new MyList() { nodeButton, nodeTextBox, nodeCheckBox };
for (int i = 0; i < myList.Count;i++)
{
this.Controls.Add(myList[i].Data);
myList[i].Data.Left = 100 * i;
}
}
}
public class MyNode
{
public MyNode(string name, Control data)
{
Data = data;
Name = name;
}
public string Name { get; private set; }
public Control Data { get; private set; }
}
public class MyList : Collection<MyNode>
{
protected override void InsertItem(int index, MyNode item)
{
base.InsertItem(index, item);
item.Data.MouseClick += new MouseEventHandler((sender, e) => { MessageBox.Show(item.Name); });
}
}
与泛型相同的例子,在编译时会产生错误:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
MyNode<Button> nodeButton = new MyNode<Button>("nodeButton", new Button());
MyNode<TextBox> nodeTextBox = new MyNode<TextBox>("nodeTextBox", new TextBox());
MyNode<CheckBox> nodeCheckBox = new MyNode<CheckBox>("nodeCheckBox", new CheckBox());
MyList myList = new MyList() { (MyNode<Control>)nodeButton, (MyNode<Control>)nodeTextBox, (MyNode<Control>)nodeCheckBox };
for (int i = 0; i < myList.Count;i++)
{
this.Controls.Add(myList[i].Data);
myList[i].Data.Left = 100 * i;
}
}
}
public class MyNode<T> where T : Control
{
public MyNode(string name, T data)
{
Data = data;
Name = name;
}
public string Name { get; private set; }
public T Data { get; private set; }
}
public class MyList : Collection<MyNode<Control>>
{
protected override void InsertItem(int index, MyNode<Control> item)
{
base.InsertItem(index, item);
item.Data.MouseClick += new MouseEventHandler((sender, e) => { MessageBox.Show(item.Name); });
}
}
根据你的说法,第一个版本是不好的做法,因为类型安全性被破坏,但第二个版本不允许类型转换!
答案 0 :(得分:9)
在这两种情况下,您都会丢失很多关于该对象的信息,并且有很多类型的安全性。铸造不愉快。您也无法确保列表仅包含特定类型的对象。
使用值类型时,性能也会显着下降;它们必须装入object
中,然后从{{1}}中拆箱,这很慢,而且不安全。
事实上,你所建议的(嗯,仍然存在)存在!它被称为ArrayList
并且非常可怕。
答案 1 :(得分:3)
来自MSDN
泛型允许您根据其所处理的精确数据类型定制方法,类,结构或接口。
当您将某些内容声明为object
时,需要在执行特定于类型的操作之前将其强制转换为相应的数据类型。同样,对于带有派生类的示例,如果仅使用基类,则会失去使用派生类的属性的能力,从而使其毫无意义。
此外,在文档中,明确提到了一个优势:
创建泛型类的实例时,指定要替换类型参数的实际类型。这将建立一个新的泛型类,称为构造的泛型类,您选择的类型将替换为类型参数出现的所有位置。结果是一个类型安全的类,根据您选择的类型进行定制。
这意味着您可以在代码中获得类型安全性。同时,您可以获得高度可重用的代码,因为您只需要插入适当的类型。
参考:http://msdn.microsoft.com/en-us/library/ms172192(v=vs.110).aspx
答案 2 :(得分:2)
因为您可以使用通用列表执行此操作:
int sum = 0;
List<int> list = GetList();
foreach(var item in list) // the compiler knows this is an int
{
sum += item; // This would not be possible with an `object`
}
注意如何允许编译器知道列表的类型,这使我可以使用列表中的对象执行操作,否则需要进行强制转换。由于我在编译时知道我正在处理什么类型的对象,因此我可以在尝试执行某些操作之前发现错误,而不是在运行此代码之前不允许这样做。
答案 3 :(得分:2)
泛型提供了许多好处,如类型安全和避免装箱和拆箱。与使用对象相比,泛型更快,因为它避免了装箱和拆箱。有关收益的更多详细信息,请参阅this,如果您是新手,请访问以下链接:
An Introduction to C# Generics
Generics (C# Programming Guide)
<强>更新强>
如果您理解类型安全的正确含义,那么您很难理解Generics
目的完全不允许用户键入强制转换对象。如果您对类型转换非常有把握,那么您可以在Cast<>()
类中编写自己的MyNode
方法,该类可以将MyNode<T1>
类型转换为MyNode<T2>
。如果你知道这个场景,并且你是否确定类型和铸件,如果你知道未来的变化不会与当前的变化发生冲突,那么就不要使用Generics
。在编程中,我们不能在每个地方使用所有东西,这完全取决于场景,并且使用最适合场景的实践。因此,您应该使用Generics
最适合的地方,并希望利用它。我希望你能理解我想要解释的内容。