c#高级教程:泛型的使用与原理和协变逆变,泛型约束和泛型缓存

 

导读:前几个月我对c#初级中级进行了回看和重温,对c#强类型语言有了自己的认识和理解,现在我们开始对c#高级教程的第一篇进行理解。

(小推荐,对c#编程的理解可以看菜鸟教程的c#编程w3cschool的c#教程

泛型的原理和使用

泛型的原理

泛型的使用是来源于c#2.0新出的规则和框架的升级,对原生需求的变更,泛型不是语法糖,是应对数据类型在传递参数的时候解决多代码冗余问题,减少代码的重复和可维护性。泛型的协变与逆变和泛型约束在c#4.0出现,解决c#出现的代码父类继承问题。

 泛型的使用

泛型使用了 未知类型泛型T的使用(延迟声明原则),需要编译器支持+JIT支持,不写死参数类型,调用时才指定的类型。

IEnumerable<IFather> IeFather = new List<Son>();  //这是泛型自己封装的泛型类型,支持多种类型的集合,列表中集合的一种。

在定义泛型之前,我们自己先定义几个方法和类。

#region   类型

public class Brid
{
public int id { get; set; }
}   //鸟类
public class Parrot : Brid
{
//public new int id { get; set; }
}//子类  老鹰
public class eagele : Brid
{
public new int id { get; set; }
}//子类鹦鹉
///1
/// <summary>
/// 父接口
/// </summary>
public class IFather
{
public int id { get; set; }
void Say() { }
} //父类
/// <summary>
/// 子类实现
/// </summary>
public class Son : IFather
{
public new int id { get; set; }
}
#endregion

 

泛型的简单定义

接口类型的泛型定义 :  public interface Ifather<T>();   //接口定义

类的泛型的定义: public  class GenericClass<T>();   //类型定义

委托泛型的定义:public delegate void deGeneric<T>();//泛型委托<T>

作为回调函数的方法: public T main<T>() { return default(T); }//泛型<t>方法

泛型的实例化:     父接口<T> 父类 = new 子类<T>();

泛型的协变和逆变的定义

#region 逆变的接口和类型 的 泛型
/// <summary>
/// 1  接口泛型 in 逆变
/// </summary>
/// <typeparam name=”T”></typeparam>
public interface IMyGeneric<in T>
{
int id { get; set; }
}
public class MyGeneric<T> : IMyGeneric<T>  //子类继承父类
{
public MyGeneric()
{
Console.WriteLine(“————-逆变方法1的构造函数启动—————-“);

}
public int id { get; set; }
}

public interface IMyGenericIn<in T, out T1>
{
void show(T Value);
T1 Get();
T1 GetValue(T Value);
}
public class MyGenericIn<T, T1> : IMyGenericIn<T, T1>
{
public MyGenericIn()
{
Console.WriteLine(“————-逆变方法2的构造函数启动—————-“);

}
public void show(T Value)
{
Console.WriteLine($”获取t类型{typeof(T)}获取当前t成员名称{typeof(T).Name}获取值为{Value}”);
}
public T1 Get()
{
return default(T1);
}
public T1 GetValue(T Value)
{
Console.WriteLine($”T类型为{Value.GetType().Name}”);
return default(T1);
}
}

#endregion

#region 协变的接口和类型 的 泛型
/// <summary>
/// 2 接口泛型 out 协变
/// </summary>
///
///
/// <typeparam name=””>一个类型T的协变</typeparam>
public interface IMyGenericOut<out T>
{
int id { get; set; }
}
public class MyGenericOut<T> : IMyGenericOut<T>
{
public int id    { get; set; }
public MyGenericOut(){
Console.WriteLine(“————-协变方法1的构造函数启动—————-“);
}
}
/// <summary>
/// 2 接口泛型的 out 协变 带多参数 并且out in的参数表现形式区别
/// </summary>
/// <typeparam name=”T”></typeparam>
/// <typeparam name=”T1″></typeparam>
public interface IMyGenericOutIn<out T, in T1>
{
T outAction(); //out要具有返回值的
void InAction(T1 t); //in要是具备传入参数的功能
// in out 传参数据形式不要忘记
}
public class MyGenericOutIn<T, T1> : IMyGenericOutIn<T, T1>
{
public MyGenericOutIn()
{
Console.WriteLine(“————-协变逆变方法2的构造函数启动—————-“);
}
public T outAction()
{
return default(T);
}
public void InAction(T1 t)
{

}
}

#endregion

现在我们来对上述协变逆变方法进行调用

public class Generic
{
public int id { get; }
public Generic()
{

//IEnumerable<Out T>   协变 支持返回结果
//协变
//1个t泛型的协变
IEnumerable<IFather> IeFather = new List<Son>();
IMyGenericOut<IFather> IeFather1 = new MyGenericOut<Son>();

//2个t 泛型的协变和逆变
IMyGenericOutIn<IFather, eagele> ieoutin =new MyGenericOutIn<Son,Brid>();
//
//逆变
//1个t泛型的逆变
// List<Son> ListSon = new IEnumerable<Father>(); //
IMyGeneric<Son> IBrid = new MyGeneric<IFather>();
//IMyGeneric是泛型的in 支持父类Ifather变子类Son不支持子类变父类
IMyGeneric<eagele> Ieagele = new MyGeneric<Brid>();
//2个t泛型的逆变和协变
IMyGenericIn<Son, IFather> GenericInOut = new MyGenericIn<IFather,Son>();

}

泛型约束


/// <summary>
/// 泛型约束
/// </summary>
public class Genericwhere//<T>泛型类
{
public static T GenericT<T>()
//返回t泛型
//泛型<T>
// where T:class//泛型约束变量类型
// where T : struct//泛型约束值类型
// where T : IEnumerable<Generic>//泛型约束接口类型
// where T : Generic //泛型约束类
// where T : new () //无参数构造函数委托
{

// T.ToString();
// T a = default(T);
// T.Where();
// int id = T.id;
// T newType = new T();
return default(T);
}
}

泛型的缓存

static类型是长驻在内存中,gc回收机制不回收此静态类型。我们可以利用这个类型描述泛型缓存。


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Test
{
//class GenericCacheValue<T>
// {
// int key { get; set; }
// T TypeName { get; set; }

// }

public class GenericCache<T,T1>
{
static GenericCache(){ //static构造函数在内存中不会清除,在调用时会调用上此构造函数,如果此方法不带上staic,在静态调用中不属于同一个区域调度,所以不会调用
Console.WriteLine(“—-在这里读取数据库中的值然后加载缓存——“);
}
public static Dictionary<T,T1> dic =new Dictionary<T, T1>();//泛型缓存
public static void CacheAdd(T key,T1 value)
{
Thread.Sleep(10);
dic.Add(key,value);
}
public static object GetCache(T Key)
{
if (dic[Key]==null)
{
return null;
}else
{
return dic[Key];
}
}
}

public class GenericTest
{
// GenericCache<string, string> cache = new GenericCache<string, string>();
public static void Test()
{
for (int i=0;i<5;i++)
{
Console.WriteLine(“—————-“);
//主线程调用时会调用类的构造函数,然后就开始增加
GenericCache<string, string>.CacheAdd($”{i}”, $”test{i}” + DateTime.Now.ToString(“yyyyyMMddhhmmss-ffff”));
//主线程在调用时泛型<T>的值与前面的值不相同,在内存中开辟另一个dic,然后实例化开始增加行为
GenericCache<int, string>.CacheAdd(i, $”test{i}” + DateTime.Now.ToString(“yyyyyMMddhhmmss-ffff”));
Console.WriteLine(i+”增加中”);
}
//下面的获取,前面的增加方法已经对泛型<T,T1>进行了实例化,下面的获取不用再次实例化,直接调度就行

for (int i=0;i<5;i++) {
Console.WriteLine(“string”+GenericCache<string, string>.GetCache($”{i}”));
Console.WriteLine(“————————–“);
Console.WriteLine(“int”+GenericCache<int, string>.GetCache(i));
}
// Dictionary<int,string> dic = GenericCache
// <int,string>.dic;
}
}

}

www.chaoyangyouth.cn

  文章链接:  www.chaoyangyouth.cn

猜你喜欢

转载自blog.csdn.net/zbq2017/article/details/81413645