Generic 泛型
{
T temp;
temp = lhs;
lhs = rhs;
rhs = temp;
}
Swap<Int>(a,b) 或者Float a, Float b; Swap<Float>(a, b) 甚至Swap(a,b) 编译器完成自动推断参数类型.
这个就是C#泛型的小例子, 反映了泛型的第一个好处 "代码复用"。
泛型,是在C++就已经有的事物了。我们知道C#是从2.0才开始支持的。泛型的好处就是代码复用,效率更高,类型安全。
泛型就是参数化类型,将类型抽象化。类型实例化时由用户制定具体类型,由编译器在JIT编译时替代为真实的类型。
{
#region ArrayList
/***************************************************************************
* ArrayList的缺点:每一个成员都必须是object对象
*1:处理值类型时,出现装箱、折箱操作,影响性能。list1.Add(1)时会发生装箱。
*2:处理引用类型时,虽没有装箱和折箱操作,但仍需要类型转换操作。
*3:程序运行时的类型转换可能引发异常。运行(int)list1[1]时,由于它是一个字符串,强制转换成int就会有异常。
***************************************************************************/
ArrayList list1 = new ArrayList();
list1.Add(1);
list1.Add("a");
int i = (int)list1[0] + 1;
#endregion
它的IL代码:可以再次看出ArrayList里存储的都是object引用,Add 和 list[0]要经历装箱拆箱。
IL_0000: nop
IL_0001: newobj instance void [mscorlib]System.Collections.ArrayList::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldc.i4.1
IL_0009: box [mscorlib]System.Int32
IL_000e: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
IL_0013: pop
IL_0014: ldloc.0
IL_0015: ldstr "a"
IL_001a: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
IL_001f: pop
IL_0020: ldloc.0
IL_0021: ldc.i4.0
IL_0022: callvirt instance object [mscorlib]System.Collections.ArrayList::get_Item(int32)
IL_0027: unbox.any [mscorlib]System.Int32
IL_002c: ldc.i4.1
IL_002d: add
IL_002e: stloc.1
* 泛型用一个通用的数据类型T来代替object,在类实例化时指定T的类型,
*CLR自动编译为本地代码,
* 并且保证数据类型安全。
* 泛型优点:
* 1:类型安全的。例如实例化了int类型的类,就不能处理string类型的数据。
*下面的list2.Add("a"),就会报错。
* 2:处理值类型时,无需装箱和折箱。int j=i+1;i可以直接取,并不需要折箱操作。
* 3:无需类型转换,包含值类型和引用类型。
**************************************************************************/
List<int> list2 = new List<int>();
list2.Add(1);
//list2.Add("a");
int j = (int)list2[0] + 1;
#endregion
对应IL
.locals init ([0] class [mscorlib]System.Collections.Generic.List`1<int32> list2,
[1] int32 j,
[2] int32 a,
[3] float32 b,
[4] float32 c) 这几个j a b c是定义的局部变量
IL_0000: nop
IL_0001: newobj instance void class [mscorlib]System.Collections.Generic.List`1<int32>::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldc.i4.1
IL_0009: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
IL_000e: nop
IL_000f: ldloc.0
IL_0010: ldc.i4.0
IL_0011: callvirt instance !0 class [mscorlib]System.Collections.Generic.List`1<int32>::get_Item(int32)
IL_0016: ldc.i4.1
IL_0017: add
IL_0018: stloc.1
泛型类中的静态成员变量:静态成员变量在相同封闭类间共享,不同的封闭类间不共享。
{
/// <summary>
/// 静态变量
/// </summary>
public static T width;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="_width"></param>
public Point(T _width)
{
width = _width;
}
/// <summary>
/// 输出width值
/// </summary>
/// <returns></returns>
public override string ToString()
{
return width.ToString();
}
}
Point<int> point = new Point<int>(1);
Point<int> point1 = new Point<int>(2);
Point<long> point2 = new Point<long>(2);
Console.WriteLine(point.ToString()); //结果为2
Console.WriteLine(point1.ToString()); //结果为2
Console.WriteLine(point2.ToString()); //结果为2
前半部分出处不记得了,后半部分出自
http://msdn.microsoft.com/en-us/library/ms379564(VS.80).aspx#csharp_generics_topic10
Contents
Generics and the .NET Framework
Inheritance and Generic
l When deriving from a generic base class, you must provide a concrete type argument instead of the base-class's generic type parameter:
派生类不是泛型类,则需要提供具体化类型。
public class BaseClass<T>
{...}
public class SubClass : BaseClass<int>
{...}
l If the subclass is generic, instead of a concrete type argument, you can use the subclass generic type parameter as the specified type for the generic base class(有点拗口,但make sense):
派生类也是泛型类,则可以用泛型类型传导
public class SubClass<T> : BaseClass<T>
{...}
l When using the subclass generic type parameters, you must repeat any constraints stipulated at the base class level at the subclass level. For example, derivation constraint:
基类的约束,派生类必须重复一遍
public class BaseClass<T> where T : ISomeInterface
{...}
public class SubClass<T> : BaseClass<T> where T : ISomeInterface
{...}
Or constructor constraint:
public class BaseClass<T> where T : new()
{
public T SomeMethod()
{
return new T();
}
}
public class SubClass<T> : BaseClass<T> where T : new()
{...}
l A base class can define virtual methods whose signatures use generic type parameters. When overriding them, the subclass must provide the corresponding types in the method signatures:
public class BaseClass<T>
{
public virtual T SomeMethod()
{...}
}
public class SubClass: BaseClass<int>
{
public override int SomeMethod()
{...}
}
If the subclass is generic it can also use its own generic type parameters for the override:
public class SubClass<T>: BaseClass<T>
{
public override T SomeMethod()
{...}
}
l You can define generic interfaces, generic abstract classes, and even generic abstract methods. These types behave like any other generic base type:
public interface ISomeInterface<T>
{
T SomeMethod(T t);
}
public abstract class BaseClass<T>
{
public abstract T SomeMethod(T t);
}
public class SubClass<T> : BaseClass<T>
{
public override T SomeMethod(T t)
{...)
}
l There is an interesting use for generic abstract methods and generic interfaces. In C# 2.0, it is impossible to use operators such as + or += on generic type parameters. For example, the following code does NOT compile because C# 2.0 does not have operator constraints:
public class Calculator<T>
{
public T Add(T arg1,T arg2)
{
return arg1 + arg2;//Does not compile
}
//Rest of the methods
}
Workaround 1---
Nonetheless, you can compensate using abstract methods (or preferably interfaces) by defining generic operations. Since an abstract method cannot have any code in it, you can specify the generic operations at the base class level, and provide a concrete type and implementation at the subclass level:
public abstract class BaseCalculator<T>
{
public abstract T Add(T arg1,T arg2);
public abstract T Subtract(T arg1,T arg2);
public abstract T Divide(T arg1,T arg2);
public abstract T Multiply(T arg1,T arg2);
}
public class MyCalculator : BaseCalculator<int>
{
public override int Add(int arg1, int arg2)
{
return arg1 + arg2;
}
//Rest of the methods
}
Workaround 2---A generic interface will yield a somewhat cleaner solution as well:
public interface ICalculator<T>
{
T Add(T arg1,T arg2);
//Rest of the methods
}
public class MyCalculator : ICalculator<int>
{
public int Add(int arg1, int arg2)
{
return arg1 + arg2;
}
//Rest of the methods
}
Generic Methods
public class MyClass<T>
{
public void MyMethod<X>(X x)
{.
//In C# 2.0, a method can define generic type parameters, specific to its execution scope
}
}
This is an important capability because it allows you to call the method with a different type every time, which is very handy for utility classes.
l You can define method-specific generic type parameters even if the containing class does not use generics at all:
public class MyClass
{
public void MyMethod<T>(T t)
{...}
}
Note: This ability is for methods only. Properties or indexers can only use generic type parameters defined at the scope of the class.
When calling a method that defines generic type parameters, you can provide the type to use at the call site:
MyClass obj = new MyClass();
obj.MyMethod<int>(3);
C# compiler is smart enough to infer the correct type based on the type of parameter passed in, it allows omitting the type specification altogether(省略类型规范<int>):
MyClass obj = new MyClass();
obj.MyMethod(3);
This ability is called generic type inference(泛型类型推断).
Note that the compiler cannot infer the type based on the type of the returned value alone:
public class MyClass
{
public T MyMethod<T>()
{}
}
MyClass obj = new MyClass();
int number = obj.MyMethod();//Does not compile
When a method defines its own generic type parameters, it can also define constraints for these types:
public class MyClass
{
public void SomeMethod<T>(T t) where T : IComparable<T>
{...}
}
然而, 你不能为class-level generic type parameters提供method-level constraints.
All constraints for class-level generic type parameters must be defined at the class scope.
When overriding a virtual method that defines generic type parameters, the subclass method must redefine the method-specific generic type parameter:
public class BaseClass
{
public virtual void SomeMethod<T>(T t)
{...}
}
public class SubClass : BaseClass
{
public override void SomeMethod<T>(T t)
{...}
}
The subclass implementation must repeat all constraints that appeared at the base method level:
public class BaseClass
{
public virtual void SomeMethod<T>(T t) where T : new()
{...}
}
public class SubClass : BaseClass
{
public override void SomeMethod<T>(T t) where T : new()
{...}
}
Note that the method override 不能定义新的constraint;
In addition, if the subclass method calls the base class implementation of the virtual method, it must specify the type argument to use instead of the generic base method type parameter. You can either explicitly specify it yourself or rely on type inference if it is available:
public class BaseClass
{
public virtual void SomeMethod<T>(T t)
{...}
}
public class SubClass : BaseClass
{
public override void SomeMethod<T>(T t)
{
base.SomeMethod<T>(t);
base.SomeMethod(t);
}
}
Generic Static Method
public class MyClass<T>
{
public static T SomeMethod(T t)
{...}
}
int number = MyClass<int>.SomeMethod(3);
Static methods can define method-specific generic type parameters and constraints, similar to instance methods. When calling such methods, you need to provide the method-specific types at the call site, either explicitly:
public class MyClass<T>
{
public static T SomeMethod<X>(T t,X x)
{..}
}
int number = MyClass<int>.SomeMethod<string>(3,"AAA");
Or rely on type inference when possible:
int number = MyClass<int>.SomeMethod(3,"AAA");
Generic static methods are subjected to all constraints imposed on the generic type parameter they use at the class level. As with instance method, you can provide constraints for generic type parameters defined by the static method:
public class MyClass
{
public static T SomeMethod<T>(T t) where T : IComparable<T>
{...}
}
C# 中的运算符只是静态方法而已,并且 C# 允许您为自己的泛型类重载运算符。
Imagine that the generic LinkedList provided the + operator for concatenating linked lists. The + operator enables you to write the following elegant code:
LinkedList<int,string> list1 = new LinkedList<int,string>();
LinkedList<int,string> list2 = new LinkedList<int,string>();
...
LinkedList<int,string> list3 = list1+list2;
Code block 7 shows the implementation of the generic + operator on the LinkedList class. Note that operators cannot define new generic type parameters.
Code block 7. Implementing a generic operator
public class LinkedList<K,T>
{
public static LinkedList<K,T> operator+(LinkedList<K,T> lhs,
LinkedList<K,T> rhs)
{
return concatenate(lhs,rhs);
}
static LinkedList<K,T> concatenate(LinkedList<K,T> list1,
LinkedList<K,T> list2)
{
LinkedList<K,T> newList = new LinkedList<K,T>();
Node<K,T> current;
current = list1.m_Head;
while(current != null)
{
newList.AddHead(current.Key,current.Item);
current = current.NextNode;
}
current = list2.m_Head;
while(current != null)
{
newList.AddHead(current.Key,current.Item);
current = current.NextNode;
}
return newList;
}
//Rest of LinkedList
}
Generic Delegates
public class MyClass<T>
{
public delegate void GenericDelegate(T t);
public void SomeMethod(T t)
{...}
}
MyClass<int>.GenericDelegate del;
del = new MyClass<int>.GenericDelegate(obj.SomeMethod);
del(3);
C# 2.0 allows you to make a direct assignment of a method reference into a delegate variable:
MyClass<int> obj = new MyClass<int>();
MyClass<int>.GenericDelegate del = obj.SomeMethod;
I am calling this feature delegate inference.
The compiler is capable of inferring the type of the delegate you assign into, finding if the target object has a method by the name you specify(has method SomeMethod),
and verifying that the method's signature matches. Then, the compiler creates a new delegate of the inferred argument type(including the correct type instead of the generic type parameter), (new MyClass<int>.GenericDelegate(obj.SomeMethod)
and assigns the new delegate into the inferred delegate.
Code block . Generic event handling
public delegate void GenericEventHandler<S,A>(S sender,A args);
public class MyPublisher
{
public event GenericEventHandler<MyPublisher,EventArgs> MyEvent;
public void FireEvent()
{
MyEvent(this,EventArgs.Empty);
}
}
public class MySubscriber<A> //Optional: can be a specific type
{
public void SomeMethod(MyPublisher sender,A args)
{...}
}
MyPublisher publisher = new MyPublisher();
MySubscriber<EventArgs> subscriber = new MySubscriber<EventArgs>();
publisher.MyEvent += subscriber.SomeMethod;
Obviously, if you need more parameters, you can simply add more generic type parameters, 但是我想模仿按如下方式定义的 .NET EventHandler 来设计 GenericEventHandler::
public void delegate EventHandler(object sender,EventArgs args);
不像 EventHandler, GenericEventHandler 是类型安全的, as shown in Code block.
Because it accepts only objects of the type MyPublisher as senders, rather than mere Object. In fact, .NET already defines a generic flavor of EventHandler in the System namespace:
public void delegate EventHandler(object sender,A args) where A : EventArgs;
Generics and Reflection
C#2.0中,反射对泛型的支持:类型 Type 现在可以表示带有特定类型实参(称为绑定类型)或未指定(未绑定)类型的一般类型。
使用 typeof 运算符或者通过调用每个类型支持的 GetType() 方法来获得任何类型的 Type。不管您选择哪种方式,都会产生相同的 Type
LinkedList<int,string> list = new LinkedList<int,string>();
Type type1 = typeof(LinkedList<int,string>);
Type type2 = list.GetType();
Debug.Assert(type1 == type2);
typeof 和 GetType() 都可以对一般类型参数进行操作:
public class MyClass
{
public void SomeMethod(T t)
{
Type type = typeof(T);
Debug.Assert(type == t.GetType());
}
}
此外,typeof 运算符还可以对未绑定的一般类型进行操作。例如:
public class MyClass<T>
{}
Type unboundedType = typeof(MyClass<>);
Trace.WriteLine(unboundedType.ToString());
//Writes: MyClass`1[T]
所追踪的数字 1 是所使用的一般类型的一般类型参数的数量。请注意空 <> 的用法。要对带有多个类型参数的未绑定一般类型进行操作,请在 <> 中使用“,”:
public class LinkedList<K,T>
{...}
Type unboundedList = typeof(LinkedList<,>);
Trace.WriteLine(unboundedList.ToString());
//Writes: LinkedList`2[K,T]
Type 具有新的方法和属性,用于提供有关该类型的一般方面的反射信息
Using Type for generic reflection
LinkedList<int,string> list = new LinkedList<int,string>();
Type boundedType = list.GetType();
Trace.WriteLine(boundedType.ToString());
//Writes: LinkedList`2[System.Int32,System.String]
Debug.Assert(boundedType.HasGenericArguments);
Type[] parameters = boundedType.GetGenericArguments();
Debug.Assert(parameters.Length == 2);
Debug.Assert(parameters[0] == typeof(int));
Debug.Assert(parameters[1] == typeof(string));
Type unboundedType = boundedType.GetGenericTypeDefinition();
Debug.Assert(unboundedType == typeof(LinkedList<,>));
Trace.WriteLine(unboundedType.ToString());
//Writes: LinkedList`2[K,T]
As in C# 1.1, you can use MethodInfo (as well as a number of other options) for late binding invocation. However, the type of the parameters you pass for the late binding must match the bounded types used instead of the generic type parameters (if any):
LinkedList<int,string> list = new LinkedList<int,string>();
Type type = list.GetType();
MethodInfo methodInfo = type.GetMethod("AddHead");
object[] args = {1,"AAA"};
methodInfo.Invoke(list,args);
Generics and the .NET Framework
System.Array and Generics
The System.Array type is extended with many generic static methods
它用从 1 到 20 的所有整数初始化一个数组。然后,代码通过一个匿名方法和 Action 委托,使用 Array.ForEach() 方法来跟踪这些数字。使用第二个匿名方法和 Predicate 委托,代码通过调用 Array.FindAll() 方法(它返回另一个相同的一般类型的数组),来查找该数组中的所有质数。最后,使用相同的 Action 委托和匿名方法来跟踪这些质数。
int[] numbers = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
Action<int> trace = delegate(int number)
{
Trace.WriteLine(number);
};
Predicate<int> isPrime = delegate(int number)
{
switch(number)
{
case 1:case 2:case 3:case 5:case 7:
case 11:case 13:case 17:case 19:
return true;
default:
return false;
}
};
Array.ForEach(numbers,trace);
int[] primes = Array.FindAll(numbers,isPrime);
Array.ForEach(primes,trace);
Generic Collections
The data structures in System.Collections are all Object-based, and thus inheriting the two problems described at the beginning of this article, namely, inferior performance and lack of type safety. .NET 2.0 introduces a set of generic collections in the System.Collections.Generic namespace.
Mapping System.Collections.Generic to System.Collections
System.Collections.Generic |
System.Collections |
Comparer<T> |
Comparer |
Dictionary<K,T> |
HashTable |
LinkedList<T> |
- |
List<T> |
ArrayList |
Queue<T> |
Queue |
SortedDictionary<K,T> |
SortedList |
Stack<T> |
Stack |
ICollection<T> |
ICollection |
IComparable<T> |
System.IComparable |
IDictionary<K,T> |
IDictionary |
IEnumerable<T> |
IEnumerable |
IEnumerator<T> |
IEnumerator |
IList<T> |
IList |
出处:http://www.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。