一:Object 类型:一切类型的父类,通过继承,子类拥有父类一切属性和行为;任何父类出现的地方,都可以用子类来代替;
用一个方法来完成多个方法做的事
/// <summary>
/// 普通方法类
/// </summary>
public class CommonMethod
{
/// <summary>
/// 打印个int值
/// </summary>
/// <param name="iParameter"></param>
public static void ShowInt(int iParameter)
{
Console.WriteLine("This is {0},parameter={1},type={2}",
typeof(CommonMethod).Name, iParameter.GetType().Name, iParameter);
}
/// <summary>
/// 打印个string值
/// </summary>
/// <param name="sParameter"></param>
public static void ShowString(string sParameter)
{
Console.WriteLine("This is {0},parameter={1},type={2}",
typeof(CommonMethod).Name, sParameter.GetType().Name, sParameter);
}
/// <summary>
/// 打印个object值
/// </summary>
/// <param name="oParameter"></param>
public static void ShowObject(object oParameter)
{
Console.WriteLine("This is {0},parameter={1},type={2}",
typeof(CommonMethod), oParameter.GetType().Name, oParameter);
}
Typeof():用来获取某个类型
缺点:
第一:object是应用类型的,所以把值类型的参数传入ShowObject()方法时,就会存在装箱和拆箱,影响性能
第二:传入参数里面的属性值无法被访问到
第三:涉及到类型安全的问题
二:泛型(不属于语法糖,是ClR升级后才支持的语法)
用途:对于不同类型的参数,具有相同行为的时候,希望代码能重用起来,这时候使用泛型
原理: /// 延迟申明:申明方法的时候并没有指定参数类型(实际存在两个参数:T是类型参数,oParameter是真实参数),而是等到使用的时候在指定
/// 延迟思想:推迟一切可以推迟的
/// 编译的时候,类型参数编译为占位符,在程序真实运行的时候,JIT进行即时编译替换为真实类型
public class GenericMethod
{
/// <summary>
/// 第一:泛型方法(方法名字后面带上尖括号,类型参数),尖括号类可以是任何没定义的任何字母或者类型,不要写关键字,不要把定义好的类写在里面
/// </summary>
/// <param name="oParameter"></param>
public static void Show<T>(T oParameter)
{
Console.WriteLine("This is {0},parameter={2},type={1}",
typeof(CommonMethod), oParameter.GetType().Name, oParameter);
}
}
class Program
{
static void Main(string[] args)
{
int iValue = 123;
object ovalue=new object();
//第一:泛型方法调用
GenericMethod.Show<int>(ivalue);
GenericMethod.Show(ivalue);//不指定类型参数,编译器自动推算
GenericMethod.Show<string>(ivalue);//此时报错,<类型参数>和参数类型:(ivalue)的类型必须吻合
GenericMethod.Show<object>(ovalue);
}
}
三:泛型类/接口
//泛型类
public class GenericClass<M,T,S>
{
public void Show(M m){}//可以作为参数
public T get(){}//可以作为返回值
}
//泛型接口
publuc interInface IStudy<T>
{
T Study(T t);
}
//泛型委托
public delegate T GetHandler<T>();
//普通类
public class Child
:GenericClass<M,T,S>//报错普通类不能直接继承泛型类
:GenericClass<int,string,double>//指定类型参数后才可以继承
:IStudy<T>//报错普通类不能直接实现泛型接口
:IStudy<string>//指定类型后可以
{
public string Study(string t){}
}
//泛型类
public class GenericChils<M,T>//等于申明了两个局部类型 M,T
:GenericClass<M,T,String>//泛型类可以直接继承泛型类
:IStudy<T>//T和M都可以或者指定一个特定类型,除此之外不行,泛型类可以直接实现泛型接口
{
T IStudy<T>.Study(T t){}
}
四:泛型约束
public class People
{
public int Id { get; set; }
public string Name { get; set; }
public void Hi(){ }
}
public class Chinese :People:ISports
{
public void SayHi(){}
public void Pingpang(){}
}
public interface ISports
{
void Pingpang();
}
public class Constraint
{
///基类约束
/// 1: 基类约束,就可以访问基类的属性和方法
/// 2:被调用时, 参数必须是基类/子类
public static void Show<T>(T oParameter) where T:People{}
//接口约束
public static void ShowInterface<T>(T oParameter) where T:ISports{}
///接口+基类约束
public static void ShowBasic<T>(T oParameter) where T:People,ISports{}
public static T Get<T>()
//where T:Class//应用了类型约束
//where T:struce//值类型约束
//where T:new()//无参数构造函数约束
{
T t=new T();
return null;//应用类型默认值
return default(T):值类型默认值
}
}
泛型方法的约束的调用:
People people = new People()
Chinese chinese = new Chinese()
Constraint.Show<People>(People p)
Constraint.Show(people )
Constraint.Show<Chinese >(Chinese p)
Constraint.Show(chinese )
Constraint.ShowInterface(people)
五:泛型的协变/逆变(out/in):只能放在接口或者委托的参数前面,类没有协变逆变
out 协变 convariant 修饰返回值
in 逆变 contravariant 修饰传入参数 IEnumerable<int> Action<int>
第一:协变
定义两个普通类
public class Bird{public int ID{get;set;}}
public class Sparrow:Bird{public string Name{get;set;}}
List<Bird> b1list=new List<bird>();------编译正确
List<Bird> B2list=new List<Sparrow>();------编译错误,因为list<Bird>和List<Sparrow>不是父子关系,没有继承关系
但是实际工作中会有这种需要(用父类集合来接受子类的集合)
一般的写法:List<Bird> B3list=new List<Sparrow>().select(c=>(Bird)c).ToList();-----编译正确,类型进行了强转
简单的写法:IEnumerable<Bird> b1=new List<bird>();---------协变
IEnumerable<Bird> b2=new List<Sparrow>();---------协变(实际上也存在类型的的转换,只不过是编译器来做,减少了代码量)
以上写法采用协变使用系统提供的IEnumerable<out T>
public interface IEnumerable<out T> : IEnumerable ------ 系统对IEnumerable<out T>的定义
使用List来接受子类集合会报错是因为,系统本身本没有对list进行协变定义
public class List<T>:IList<T>,IEnumerable<T>..........----------- 系统对List<T>的定义 参数没有Out
原因:List出现在.net2.0版本,而IEnumerable<out T>出现在C#4.0版本,两个不是属于同一个时期出现
自定义协变接口
Public interface ICustomerListOut<out T>
{
T Get();-----正确
void Show(T t)----报错,T不能作为传入参数,只能是返回结果;
}
//类没有协变逆变
public class CustomerListOut<T>:ICustomerListOut<T>
{
public T Get(){return default(T);}
}
使用:
ICustomerListOut<Bird> b=new CustomerListOut<Bird>();
ICustomerListOut<Bird> b=new CustomerListOut<Sparrow>();
第二:逆变
自定义逆变接口
Public interface ICustomerListOut<in T>
{
//T Get();-----报错,T只能作为传入参数,不能是返回结果;
void Show(T t)----正确
}
public class CustomerListOut<T>:ICustomerListOut<T>
{
public void Show(T t){}
}
使用:
ICustomerListIn<Sparrow> customerList2 = new CustomerListIn<Sparrow>();
ICustomerListIn<Sparrow> customerList1 = new CustomerListIn<Bird>();
第三:逆变+协变(实际工作中使用很少,一般使用系统很少自己定义,系统自带Func<in T,out Tresult>)
public interface IMyList<in inT, out outT>
{
void Show(inT t);
outT Get();
outT Do(inT t);
}
public class MyList<T1, T2> : IMyList<T1, T2>
{
public void Show(T1 t)
{
Console.WriteLine(t.GetType().Name);
}
public T2 Get()
{
Console.WriteLine(typeof(T2).Name);
return default(T2);
}
public T2 Do(T1 t)
{
Console.WriteLine(t.GetType().Name);
Console.WriteLine(typeof(T2).Name);
return default(T2);
}
}
使用:
IMyList<Sparrow, Bird> myList1 = new MyList<Sparrow, Bird>();
IMyList<Sparrow, Bird> myList2 = new MyList<Sparrow, Sparrow>();//协变
IMyList<Sparrow, Bird> myList3 = new MyList<Bird, Bird>();//逆变
IMyList<Sparrow, Bird> myList4 = new MyList<Bird, Sparrow>();//协变+逆变
第六:泛型的缓存
一般采用字典缓存:定义一个静态属性
/// <summary>
/// 字典缓存:静态属性常驻内存
/// </summary>
public class DictionaryCache
{
private static Dictionary<string, string> _TypeTimeDictionary = null;
static DictionaryCache()
{
Console.WriteLine("This is DictionaryCache 静态构造函数");
_TypeTimeDictionary = new Dictionary<string, string>();
}
public static string GetCache<T>()
{
Type type = typeof(T);
if (!_TypeTimeDictionary.ContainsKey(type.Name))
{
_TypeTimeDictionary[type.Name] = string.Format("{0}_{1}", typeof(T).FullName, DateTime.Now.ToString("yyyyMMddHHmmss.fff"));
}
return _TypeTimeDictionary[type.Name];
}
}
第二:泛型缓存
原理:利用泛型每次在运行时Jit即时编译生成不同的副本
使用场景:用来保存固定数据,适合不同类型,需要缓存一份数据的场景,
优点:效率高
缺点:不能清除被回收
/// <summary>
/// 每个不同的T,在运行的时候JIT都会生成一份不同的副本,用于保存不同的T
/// </summary>
/// <typeparam name="T"></typeparam>
public class GenericCache<T>
{
static GenericCache()
{
Console.WriteLine("This is GenericCache 静态构造函数");
_TypeTime = string.Format("{0}_{1}", typeof(T).FullName, DateTime.Now.ToString("yyyyMMddHHmmss.fff"));
}
private static string _TypeTime = "";
public static string GetCache()
{
return _TypeTime;
}
}
调用:
for (int i = 0; i < 5; i++)
{
Console.WriteLine(GenericCache<int>.GetCache());
Thread.Sleep(10);
Console.WriteLine(GenericCache<long>.GetCache());
}