如我在帖子中举的例, public class GenericList<T> 这里的“T”就是泛型类型参数 类型参数是客户端在实例化泛型类型的变量时指定的特定类型的占位符。也就是说定义泛型类或泛型方法时,尖括号中的参数就是泛型类型参数在使用泛型的时候,必须要用编译器能识别的类型代替尖括号中的泛型类型参数, 例如我要使用GenericList这个类,实例化的时候必须GenericList<int> g = new GenericList<int>(); 这里的int是特定的类型,不能够再用泛型
应59楼要求,说一下泛型的约束在定义泛型类时,可以对客户端代码能够在实例化类时用于类型参数的类型种类施加限制。如果客户端代码尝试使用某个约束所不允许的类型来实例化类,则会产生编译时错误。这些限制称为约束。约束是使用 where 上下文关键字指定的。下表列出了六种类型的约束:约束 说明 T:结构 类型参数必须是值类型。可以指定除 Nullable 以外的任何值类型。 T:类 类型参数必须是引用类型;这一点也适用于任何类、接口、委托或数组类型。 T:new() 类型参数必须具有无参数的公共构造函数。当与其他约束一起使用时,new() 约束必须最后指定。 T:<基类名> 类型参数必须是指定的基类或派生自指定的基类。 T:<接口名称> 类型参数必须是指定的接口或实现指定的接口。可以指定多个接口约束。约束接口也可以是泛型的。 T:U 为 T 提供的类型参数必须是为 U 提供的参数或派生自为 U 提供的参数。这称为裸类型约束。 为什么要使用约束? 比如我定义了一下一个类Employee:public class Employee { private string name; private int id; public Employee(string s, int i) { name = s; id = i; } public string Name { get { return name; } set { name = value; } } public int ID { get { return id; } set { id = value; } } } 那么我在定义另一个类的时候,我只希望传入这个类的参数是Employee类或继承自Employee类,这时候就要用泛型约束了:public class GenericList<T> where T : Employee { //to do... }这样一来,我们在GenericList<T>中就可以使用 Employee.Name 属性,因为类型为 T 的所有项都保证是 Employee 对象或从 Employee 继承的对象。可以对同一类型参数应用多个约束,并且约束自身可以是泛型类型,如下所示: class EmployeeList<T> where T : Employee, IEmployee, System.IComparable<T>, new() { // to do... }在应用 where T : class 约束时,避免对类型参数使用 == 和 != 运算符,因为这些运算符仅测试引用同一性而不测试值相等性。即使在用作参数的类型中重载这些运算符也是如此。下面的代码说明了这一点;即使 String 类重载 == 运算符,输出也为 false。public static void OpTest<T>(T s, T t) where T : class { Console.WriteLine(s == t); } static void Main() { string s1 = "ojlovecd"; System.Text.StringBuilder sb = new System.Text.StringBuilder("ojlovecd"); string s2 = sb.ToString(); OpTest<string>(s1, s2); }这种情况的原因在于,编译器在编译时仅知道 T 是引用类型,因此必须使用对所有引用类型都有效的默认运算符。如果必须测试值相等性,建议的方法是同时应用 where T : IComparable<T> 约束,并在将用于构造泛型类的任何类中实现该接口。 没有声明约束条件的称为未绑定的类型参数,就像我的帖子一开头举的那个Generic<T>类中的T就是未绑定的类型参数,如果参数未加约束的话,不能使用==和!= 运算符,因为无法保证具体类型参数能支持这些运算符。 另外还有一种约束称为裸类型约束,由于用的不多,所以我就不展开来说了
class EmployeeList<T> where T : Employee, IEmployee, System.IComparable<T>, new() { // to do... } 我是不是可以理解为where T : 后面的一起约束那个T,而继承的类和接口必须放where T : 的前面。
是的,就像这样:class EmployeeList<T> : Employee,IEmployee where T : Employee, IEmployee, System.IComparable<T>, new() { // to do... }
this.dataGridView1.DataSource = dic.Values;????//这样为什么不行
DataGridView 类支持标准的 Windows 窗体数据绑定模型。这意味着数据源可以是实现下列接口之一的任何类型:IList 接口,包括一维数组。IListSource 接口,例如,DataTable 和 DataSet 类。IBindingList 接口,例如,BindingList<T> 类。IBindingListView 接口,例如,BindingSource 类。但Dictioanry的Values属性是ValueCollection类型的,它只实现ICollection<TValue>,IEnumerable<TValue>,ICollection,IEnumerable接口,所以你不能用Dictionary的Values属性作为DataGridView的数据源
dic.Values --也是一个集合啊。为什么就不能作为数据源。
即使你继承Dictionary类,Values属性由于不是虚拟的,所以你也不能够重写
在C#3.0以上版本中,由于Linq加入了对很多集合类的扩展方法,你可以用其中的ToList()方法将其转换为List<TValue>在进行绑定:dataGridView1.DataSource = dic.Values.ToList();
或者干脆让他们看MSDN去吧
C#泛型机制:C#泛型能力由CLR在运行时支持,区别于C++的编译时的模版机制、和JAVA的编译时的“搽试法”,这使得C#泛型能力可以再各个支持CLR的语言之间进行无缝的互操作。C#泛型编译机制:
1:第一轮编译时,编译器只为stack产生“泛型版”的IL代码和元数据,并不进行泛型类型的实例化,T在中间值充当占位符。
2:JIT编译时,当JIT编译器第一次遇到stack时,将用int类型替换“泛型版”IL代码和元数据中的T进行泛型类型的实例化。
3:CLR为所有类型参数为“引用类型的”的泛型类型产生痛一份代码,但如果类型参数是“值类型”,对每个不同的“值类型”CLR将为其产生一份独立的代码。
LS有位朋友关心的问题正好也是我想知道的
就是泛型在
1:bulid前后 clr做了什么?
2:生产il后是什么状况?
3:jit又做了什么?整个过程能否稍微解释下..
据说好像是Java抄C#的。
有一部分的确是从MSDN摘的,我已经说明过了
我的理解是,泛型都是可枚举的,不用拆箱装箱,无需类型转换,无性能损失。可枚举真的是方便了使用者,什么foreach随便用,无需类型转换更是让使用者不至于出现类型转换的错误。其实我们自定义一个泛型类用来处理通用过程也是不错的,泛型类内使用反射将传入的泛型对象类型给反射出来,然后就可以操作了。
public class GenericList<T>
这里的“T”就是泛型类型参数
类型参数是客户端在实例化泛型类型的变量时指定的特定类型的占位符。也就是说定义泛型类或泛型方法时,尖括号中的参数就是泛型类型参数在使用泛型的时候,必须要用编译器能识别的类型代替尖括号中的泛型类型参数,
例如我要使用GenericList这个类,实例化的时候必须GenericList<int> g = new GenericList<int>();
这里的int是特定的类型,不能够再用泛型
T:结构 类型参数必须是值类型。可以指定除 Nullable 以外的任何值类型。
T:类 类型参数必须是引用类型;这一点也适用于任何类、接口、委托或数组类型。
T:new() 类型参数必须具有无参数的公共构造函数。当与其他约束一起使用时,new() 约束必须最后指定。
T:<基类名> 类型参数必须是指定的基类或派生自指定的基类。
T:<接口名称> 类型参数必须是指定的接口或实现指定的接口。可以指定多个接口约束。约束接口也可以是泛型的。
T:U 为 T 提供的类型参数必须是为 U 提供的参数或派生自为 U 提供的参数。这称为裸类型约束。
为什么要使用约束?
比如我定义了一下一个类Employee:public class Employee
{
private string name;
private int id; public Employee(string s, int i)
{
name = s;
id = i;
} public string Name
{
get { return name; }
set { name = value; }
} public int ID
{
get { return id; }
set { id = value; }
}
}
那么我在定义另一个类的时候,我只希望传入这个类的参数是Employee类或继承自Employee类,这时候就要用泛型约束了:public class GenericList<T> where T : Employee
{
//to do...
}这样一来,我们在GenericList<T>中就可以使用 Employee.Name 属性,因为类型为 T 的所有项都保证是 Employee 对象或从 Employee 继承的对象。可以对同一类型参数应用多个约束,并且约束自身可以是泛型类型,如下所示:
class EmployeeList<T> where T : Employee, IEmployee, System.IComparable<T>, new()
{
// to do...
}在应用 where T : class 约束时,避免对类型参数使用 == 和 != 运算符,因为这些运算符仅测试引用同一性而不测试值相等性。即使在用作参数的类型中重载这些运算符也是如此。下面的代码说明了这一点;即使 String 类重载 == 运算符,输出也为 false。public static void OpTest<T>(T s, T t) where T : class
{
Console.WriteLine(s == t);
}
static void Main()
{
string s1 = "ojlovecd";
System.Text.StringBuilder sb = new System.Text.StringBuilder("ojlovecd");
string s2 = sb.ToString();
OpTest<string>(s1, s2);
}这种情况的原因在于,编译器在编译时仅知道 T 是引用类型,因此必须使用对所有引用类型都有效的默认运算符。如果必须测试值相等性,建议的方法是同时应用 where T : IComparable<T> 约束,并在将用于构造泛型类的任何类中实现该接口。
没有声明约束条件的称为未绑定的类型参数,就像我的帖子一开头举的那个Generic<T>类中的T就是未绑定的类型参数,如果参数未加约束的话,不能使用==和!= 运算符,因为无法保证具体类型参数能支持这些运算符。
另外还有一种约束称为裸类型约束,由于用的不多,所以我就不展开来说了
泛型跟可枚举是没有必然联系的,只有实现了IEnumerable接口或具有必需的 GetEnumerator、MoveNext、Reset 和 Current()成员的类对象才可以被foreach遍历
class EmployeeList<T> where T : Employee, IEmployee, System.IComparable<T>, new()
{
// to do...
}
我是不是可以理解为where T : 后面的一起约束那个T,而继承的类和接口必须放where T : 的前面。
{
// to do...
}