【发布时间】:2008-09-30 21:51:48
【问题描述】:
我一直在学习 C# 的基础知识,但没有很好地解释这是什么:
var l = new List<string>();
我不知道 <string> 在做什么,或者是不是 List 在施展魔法。我还看到在< > 标签中抛出了对象。
谁能用例子给我解释一下?
【问题讨论】:
我一直在学习 C# 的基础知识,但没有很好地解释这是什么:
var l = new List<string>();
我不知道 <string> 在做什么,或者是不是 List 在施展魔法。我还看到在< > 标签中抛出了对象。
谁能用例子给我解释一下?
【问题讨论】:
这是 C# 的通用语法。
基本概念是它允许您使用类型占位符并在编译时替换实际的真实类型。
比如老办法:
ArrayList foos = new Arraylist();
foos.Add("Test");
通过使 ArrayList 存储 System.Objects 列表(所有事物的基本类型 .NET)来工作。
因此,当从列表中添加或检索对象时,CLR 必须将其强制转换为对象,基本上真正发生的是:
foos.Add("Test" as System.Object);
string s = foos[1] as String.
这会导致强制转换的性能损失,而且它也不安全,因为我可以这样做:
ArrayList listOfStrings = new ArrayList();
listOfStrings.Add(1);
listOfStrings.Add("Test");
即使我在 listOfStrings 中放了一个整数,也可以编译得很好。
泛型改变了这一切,现在使用泛型我可以声明我的集合期望的类型:
List<int> listOfIntegers = new List<int>();
List<String> listOfStrings = new List<String>();
listOfIntegers.add(1);
// Compile time error.
listOfIntegers.add("test");
这提供了编译时类型安全,并避免了昂贵的转换操作。
尽管有一些高级的边缘案例,但您利用它的方式非常简单。基本概念是通过使用类型占位符使您的类类型不可知,例如,如果我想创建一个通用的“添加两件事”类。
public class Adder<T>
{
public T AddTwoThings(T t1, T t2)
{
return t1 + t2;
}
}
Adder<String> stringAdder = new Adder<String>();
Console.Writeline(stringAdder.AddTwoThings("Test,"123"));
Adder<int> intAdder = new Adder<int>();
Console.Writeline(intAdder.AddTwoThings(2,2));
对于泛型的更详细解释,我不能推荐足够多的书 CLR via C#。
【讨论】:
Add(var) 中的 var 可隐式转换为 T。它是泛型——它是一种类型参数化的形式。在您的示例中,它使 l 引用字符串列表-该列表将仅包含字符串:编译器(几乎)将其视为 API 文档提到“T”的任何地方实际上都说“字符串”。因此,您只能向其添加字符串,如果您使用索引器,则不需要强制转换为字符串等。
说实话,在在线论坛上详细介绍泛型几乎是不可能的。 (在深度 C# 中,我花了将近 50 页来讨论泛型。)但是,有了特性的名称,您应该可以更好地了解更多信息。 MSDN "Introduction to C# Generics" 可能是一个很好的起点。
在 SO 上询问有关泛型的具体问题可能会产生良好的结果 - 我只是认为它不能真正在一个问题/答案中正确涵盖。
【讨论】:
这是 .NET 泛型。 中的类型表示列表中包含的元素的类型。
使用 ArrayList 你必须将元素投射到里面......
int x = (int)myArrayList[4];
使用 List 可以避免该步骤,因为编译器已经知道类型。
int x = myList[4];
泛型在 .NET 2.0 及更高版本中可用。
【讨论】:
那些是泛型。您正在制作一个仅包含字符串的列表。你也可以说
List<int>
并得到一个只包含整数的列表。
泛型是一个庞大的话题,在这里无法单独回答。
【讨论】:
那些被称为泛型(特别是List 是一个泛型类)。
从 MSDN 阅读
【讨论】:
这是泛型的作用。常规列表存储对象类型的项目。这需要类型之间的转换。这也将允许您将任何类型的项目存储在列表的一个实例中。当您遍历该列表中的项目时,您无法确定它们都是某种类型(至少在没有强制转换每个项目的情况下不能确定)。例如,假设您创建了一个这样的列表:
List listOfStrings = new List();
没有什么能阻止某人做这样的事情:
listOfStrings.add(6); //Not a string
通用列表允许您指定强类型列表。
List<string> listOfStrings = new List<string>();
listOfStrings.add("my name"); //OK
listofStrings.add(6); //Throws a compiler error
这里有更详尽的例子Generics
【讨论】:
用于泛型。在您的具体示例中,这意味着 List 是字符串列表,而不是整数列表。
泛型用于允许类型是泛型的。它在 Collections 中使用了 ALOT 以允许它们采用不同的类型,以便它们可以像普通数组一样运行,并且仍然可以捕获在编译时分配的无效类型。基本上它允许一个类说“我需要与某个特定类型 T 相关联,但我不想硬编码该类型是什么,并让用户选择它。”。例如,一个简单的数组可能看起来像:
public class MyArray<T> {
private T[] _list;
public MyArray() : this.MyArray(10);
public MyArray(int capacity)
{ _list = new T[capacity]; }
T this[int index] {
get { return _list[index]; }
set { _list[index] = value; }
}
}
在这里,我们有一个类型为 T 的私有列表,可以像普通数组一样使用我们的类来访问它。我们不关心它是什么类型,这对我们的代码无关紧要。但是使用该类的任何人都可以将其用作 MyArray<string> 来创建字符串列表,而其他人可能会将其用作 MyArray<bool> 并创建标志列表。
【讨论】: