首先我们来看一下泛型的基本概念。
最显著的一点就是它参数化了类型,把类型作为参数抽象出来,从而使我们在实际的运用当中能够更好的实现代码的重复利用,同时它提供了更强的类型安全,更高的效率,不过在约束方面,它只支持显示的约束,这样在灵活性方面就显得不是那么好了。我觉得它之所以能够提供更高的效率是因为泛型在实例化的时候采用了"on-demand"的模式,即按需实例化,发生在JIT(Just In Time)编译时。
下面来看如何定义一个泛型类,很简单,你只需要意识到一点,在这里,类型已经被参数化了:
//如果这样写的话,显然会报找不到类型T,S的错误
public class TestChild : Test<T, S> { }
//正确的写法应该是
public class TestChild : Test<string, int>{ }
public class TestChild<T, S> : Test<T, S> { }
public class TestChild<T, S> : Test<String, int> { }
public class TestChild : Test<T, S> { }
//正确的写法应该是
public class TestChild : Test<string, int>{ }
public class TestChild<T, S> : Test<T, S> { }
public class TestChild<T, S> : Test<String, int> { }
public interface IList<T>
{
T[] GetElements();
}
public interface IDictionary<K,V>
{
void Add(K key, V value);
}
// 泛型接口的类型参数要么已实例化
// 要么来源于实现类声明的类型参数
class List<T> : IList<T>, IDictionary<int, T>
{
public T[] GetElements() { return null; }
public void Add(int index, T value)
{}
}
{
T[] GetElements();
}
public interface IDictionary<K,V>
{
void Add(K key, V value);
}
// 泛型接口的类型参数要么已实例化
// 要么来源于实现类声明的类型参数
class List<T> : IList<T>, IDictionary<int, T>
{
public T[] GetElements() { return null; }
public void Add(int index, T value)
{}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace GenericTest
{
//定义一个委托,类型参数为T,返回值类型T
//泛型委托支持在返回值和参数上应用类型参数
delegate string GenericDelete<T>(T value);
class test
{
static string F(int i) { return "SHY520"; }
static string G(string s) { return "SHY520"; }
static void Main(string[] args)
{
GenericDelete<string> G1 = G;
GenericDelete<int> G2 = new GenericDelete<int>(F);
}
}
}
using System.Collections.Generic;
using System.Text;
namespace GenericTest
{
//定义一个委托,类型参数为T,返回值类型T
//泛型委托支持在返回值和参数上应用类型参数
delegate string GenericDelete<T>(T value);
class test
{
static string F(int i) { return "SHY520"; }
static string G(string s) { return "SHY520"; }
static void Main(string[] args)
{
GenericDelete<string> G1 = G;
GenericDelete<int> G2 = new GenericDelete<int>(F);
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace GenericTest
{
class GenericClass
{
//申明一个泛型方法
public T getvalue<T>(T t)
{
return t;
}
//调用泛型方法
//注意:在调用泛型方法时,对泛型方法的类型参数实例化
public int useMethod()
{
return this.getvalue<int>(10);
}
//重载getvalue方法
public int getvalue(int i)
{
return i;
}
}
//下面演示覆盖
//要注意的是,泛型方法被覆盖时,约束被默认继承,不需要重新指定约束关系
abstract class Parent
{
public abstract K TEST<K, V>(K k, V v) where K : V;
}
class Child : Parent
{
public override T TEST<T, S>(T t, S s)
{
return t;
}
}
}
using System.Collections.Generic;
using System.Text;
namespace GenericTest
{
class GenericClass
{
//申明一个泛型方法
public T getvalue<T>(T t)
{
return t;
}
//调用泛型方法
//注意:在调用泛型方法时,对泛型方法的类型参数实例化
public int useMethod()
{
return this.getvalue<int>(10);
}
//重载getvalue方法
public int getvalue(int i)
{
return i;
}
}
//下面演示覆盖
//要注意的是,泛型方法被覆盖时,约束被默认继承,不需要重新指定约束关系
abstract class Parent
{
public abstract K TEST<K, V>(K k, V v) where K : V;
}
class Child : Parent
{
public override T TEST<T, S>(T t, S s)
{
return t;
}
}
}
C#中的泛型只支持显示的约束,因为这样才能保证C#所要求的类型安全,但显示的约束并非时必须的,如果不加约束,泛型类型参数将只能
1、基类约束:
class A { public void F1() {} }
class B { public void F2() {} }
class C<S,T>
where S: A // S继承自A
where T: B // T继承自B
{
// 可以在类型为S的变量上调用F1,
// 可以在类型为T的变量上调用F2
}
class B { public void F2() {} }
class C<S,T>
where S: A // S继承自A
where T: B // T继承自B
{
// 可以在类型为S的变量上调用F1,
// 可以在类型为T的变量上调用F2
}
interface IPrintable { void Print(); }
interface IComparable<T> { int CompareTo(T v);}
interface IKeyProvider<T> { T GetKey(); }
class Dictionary<K,V>
where K: IComparable<K>
where V: IPrintable, IKeyProvider<K>
{
// 可以在类型为K的变量上调用CompareTo,
// 可以在类型为V的变量上调用Print和GetKey
}
interface IComparable<T> { int CompareTo(T v);}
interface IKeyProvider<T> { T GetKey(); }
class Dictionary<K,V>
where K: IComparable<K>
where V: IPrintable, IKeyProvider<K>
{
// 可以在类型为K的变量上调用CompareTo,
// 可以在类型为V的变量上调用Print和GetKey
}
class A { public A() { } }
class B { public B(int i) { } }
class C<T>
where T : new()
{
//可以在其中使用T t=new T();
}
C<A> c=new C<A>(); //可以,A有无参构造器
C<B> c=new C<B>(); //错误,B没有无参构造器
class B { public B(int i) { } }
class C<T>
where T : new()
{
//可以在其中使用T t=new T();
}
C<A> c=new C<A>(); //可以,A有无参构造器
C<B> c=new C<B>(); //错误,B没有无参构造器
public struct A { }
public class B { }
class C<T>
where T : struct
{
// T在这里面是一个值类型
}
C<A> c=new C<A>(); //可以,A是一个值类型
C<B> c=new C<B>(); //错误,B是一个引用类型
public class B { }
class C<T>
where T : struct
{
// T在这里面是一个值类型
}
C<A> c=new C<A>(); //可以,A是一个值类型
C<B> c=new C<B>(); //错误,B是一个引用类型