C# 进阶第一课:泛型专题,封闭与开放,泛型继承,逆变协变,泛型约束,泛型缓存

为什么需要泛型,出现背景:
代码重用,好处:
源代码保护,类型安全,更清晰的代码,更佳的性能
FCL(框架类型,相当于java中jar包)中应用最广泛的地方,就是泛型集合类,

第一个知识点:
开放类型与封闭类型,
具有泛型参数的类型称为开放类型,
为所有参数类型传递实际数据类型的类型称为封闭类型
理解:即可以赋值具体数据类型,所以称为开放类型,
不管是封闭类型,还是开放类型,本质上仍然是类型,
也有类型对象,type object,区别是,CLR允许构造封闭类型的实例,
不允许构造开放类型实例,类似的CLR禁止构造接口实例,
是一回事儿
demo:
internal sealed class DictionaryNew:Dictionary{
}
type t=Tvalue.getType("Dictionary<>");
Activitor.CreateInstance();
报错

第二个知识点:泛型继承
泛型既然也是一种类型,同样符合继承条件
internal class Node{
protected Node m_next;
public Node(Node node){
m_next=next;
}
}

internal sealed class NodeType:Node
{
public T t_data;
//必须继承base(next)
public NodeType(T data,Node n):base(next)
{
t_data=data;
}
public NodeType(T data):this(data,null)
{
}
//重点是这个
public override ToString(){
//
string res=string.Empty;
if(m_next!=null){
//将后赋值添加内容,放在后面,
//m_next内容放在前面
res=m.next.ToString()+t_data;
//很巧妙自己调用自己
}
else{
res=t_data;
}
}
第三个知识点:泛型同一性
即可声明
List listdate=new List();
简化<>优化阅读方式:
internal sealed class listdatetime:List{}
接下来直接使用
listdate ld=new listdate();
官方建议做法:
using listdate=System.Collections.Generic.List

第四个知识点:代码爆炸,泛型缓存
主要解决问题,针对泛型实参为值类型,生成不同本机代码

demo

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

namespace ConsoleApplication1
{
  
    public class TestTCache
    {
       
            static void Main(string[] args)
            {
                CjavapyCacheTest.Show();
            }
        public class CjavapyCacheTest
        {
            public static void Show()
            {
                for (int i = 0; i < 5; i++)
                {
                    Console.WriteLine(GenericCache.GetCache());
                    Thread.Sleep(10);
                    Console.WriteLine(GenericCache.GetCache());
                    Thread.Sleep(10);
                    Console.WriteLine(GenericCache.GetCache());
                    Thread.Sleep(10);
                    Console.WriteLine(GenericCache.GetCache());
                    Thread.Sleep(10);
                    Console.WriteLine(GenericCache.GetCache());
                    Thread.Sleep(10);
                }


            }
        }
        /// 
        /// 每个不同的T,都会生成一份不同的副本,
        /// 理解相当于调用几个类型,class GenericCacheInt,class GenericCacheLong,..
        /// 适合不同类型,需要缓存一份数据的场景,效率高
        /// 不能主动释放
        /// 
        /// 
        public class GenericCache
        {
            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;
            }
        }

        /// 
        /// 字典缓存:静态属性常驻内存
        /// 
        public class DictionaryCache
        {
            private static Dictionary _TypeTimeDictionary = null;
            static DictionaryCache()
            {
                Console.WriteLine("This is DictionaryCache 静态构造函数");
                _TypeTimeDictionary = new Dictionary();
            }
            public static string GetCache()
            {
                Type type = typeof(T);
                if (!_TypeTimeDictionary.ContainsKey(type))
                {
                    _TypeTimeDictionary[type] = string.Format("{0}_{1}", typeof(T).FullName, DateTime.Now.ToString("yyyyMMddHHmmss.fff"));
                }
                return _TypeTimeDictionary[type];
            }
        }
    }
 
}

这个例子也是泛型缓存的例子,可是项目实际中如何应用开发,博主也没遇到,欢迎同行留言私信交流

第五个知识点:不仅仅是类可声明泛型类型,
委托和接口也都可以声明泛型参数,称为泛型委托类型,或是泛型接口类型
委托本质上只是提供四个方法的一个类,

public delegate TReturn CallMe();

第五个知识点:委托或接口的逆变,协变泛型类型实参
逆变是针对输入的,逆变实参可接收派生类,比如方法参数
它用关键字in标记,
协变是针对输出,比如方法返回,可返回基类,
它用关键字out标记
public delegate TResult Func(T t);

Func fn1=null;

//接收一个string输入,它是object派生
//返回一个基类是可以的
Func fn2=fn1;

第六个知识点:泛型方法
不仅仅是在类,接口,委托之中定义泛型参数
方法中同样可以定义泛型参数,
//类中接收的一个泛型实参,转为方法中的一个泛型实参
public sealed class GenericType{
public T t;
//构造器给属性赋值
public GenericType(T tt){
t=tt;
}
public  TOutput Convertor(){
object o;
TOutput tt=(TOutput)Convert.ChangeType(t,typeof(TOutput));
return tt;
}
}
 public static void Swap(ref T t1,ref T t2){
            T temp;
            temp = t1;
            t1 = t2;
            t2 = temp;
       }
//可自己推断类型

第七个知识点:
在c#中,属性,索引器,事件,操作符方法,构造器,终结器
不能有泛型参数,但是能在泛型类型中进行定义,并且可使用泛型类型的的参数

第七个知识点:
泛型参数,本身可进行各种约束关键字where
 public static T Min(T t1,T t2) where T:IComparable {
            //提示没有
            if (t1.CompareTo(t2)<0)
            {
                return t1;
            }
            return t2;
        }

//T 不是进行接口约束,报错
类型,方法,不能基于约束,和参数名称进行重载

internal sealed class AanyType();
internal sealed class AanyType();
internal sealed class AanyType();

类型参数可指定零个或一个主要约束,
internal sealed class Primary where T:Stream{
 public void Me(T stream){

}
}
有两个特殊的主要约束:
class引用类型,类类型,接口类型,委托类型,数组类型
struct值类型
次要约束:
代表接口类型
类型参数约束,也是裸约束
接收一个list返回另一个list
//方法声明两个T
public List Convert(IList t) where T:TBase
{}

构造函数约束,:new()

定义必须有无参构造函数


其他知识点:
泛型类型转型,不能直接转型,必须转为object
默认值default(T)
public void Test(T t){
T t=default(T);
int x=(int)(object)t;
}

泛型目前存在的问题,在于基元值类型,
无法引用加减乘除都操作数,即便是约束泛型参数为值类型
public T sum(T t){
T temp=defaulst(T);
for(var i=0;i temp+=i;
}
return temp;
}

 

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;

namespace WaitForPendingFinalizersExample
{
    class MyWaitForPendingFinalizersClass
    {
        // You can increase this number to fill up more memory.
        //你可以增加这个数字来填满更多的内存。
        const int numMfos = 100000;
        // You can increase this number to cause more
        // post-finalization work to be done.
        //你可以增加这个数字完成终结前的工作。
        //const int maxIterations = 10;

        static void Main(string[] args)
        {
            const int c = 100000000;
            using (new TestGC("List"))
            {
                List list = new List();
                for (int i = 0; i < c; i++)
                {
                    list.Add(i);
                    int x=list[i];
                }
                list = null;

            }
            using (new TestGC("ArrayList"))
            {
                ArrayList list1 = new ArrayList();
                for (int i = 0; i < c; i++)
                {
                    list1.Add(i);
                    int x1 =(int) list1[i];
                }
                list1 = null;

            }
            using (new TestGC("List"))
            {
                List list2 = new List();
                for (int i = 0; i < c; i++)
                {
                    list2.Add("x");
                    string x = list2[i];
                }
                list2 = null;

            }
            using (new TestGC("ArrayList"))
            {
                ArrayList list3 = new ArrayList();
                for (int i = 0; i < c; i++)
                {
                    list3.Add("x");
                    string x =(string) list3[i];
                }
                list3 = null;

            }
            /*List,执行时间:625ms,垃圾回收次数:6
ArrayList,执行时间:9751ms,垃圾回收次数:393
List,执行时间:1558ms,垃圾回收次数:7
ArrayList,执行时间:1810ms,垃圾回收次数:7*/
 Console.ReadKey();
            using (new TestGC("我是循环遍历释放引用资源的测试"))
            {
                
           
            int begin_gccount,end_gccount;
            PrepareForOperation();
            begin_gccount = GC.CollectionCount(0);
            MyFinalizeObject mfo = null;

            // Create and release a large number of objects
            // that require finalization.
            /*创建和释放大量对象
这需要最后确定。*/
            for (int j = 0; j < numMfos; j++)
            {
                mfo = new MyFinalizeObject();
            }

            //Release the last object created in the loop.
            mfo = null;
            end_gccount = GC.CollectionCount(0);
            //Force garbage collection.
            //GC.Collect();

            // Wait for all finalizers to complete before continuing.
            // Without this call to GC.WaitForPendingFinalizers,
            // the worker loop below might execute at the same time
            // as the finalizers.
            // With this call, the worker loop executes only after
            // all finalizers have been called.
            /*等待所有终结器完成,然后继续。
没有这个电话等待终结器,
下面的工作循环可能同时执行
作为终结者。
通过此调用,工作循环仅在
已调用所有终结器。
             含义是等待所有终结器完成*/
            //GC.WaitForPendingFinalizers();
            //Console.WriteLine("回收次数:"+(end_gccount-begin_gccount));
            }
           
            // Worker loop to perform post-finalization code.
            //for (int i = 0; i < maxIterations; i++)
            //{
            //    Console.WriteLine("Doing some post-finalize work");
            //}
        }
        internal sealed class TestGC : IDisposable {
            private Stopwatch sw=new Stopwatch();
            private string text;
            private int count;

            //构造开始便进行一次重置
            public TestGC(string t) {
                PrepareForOperation();
                text = t;
                //同时统计一次垃圾回收次数:
                count = GC.CollectionCount(0);
                //时间重新开始计时
                sw.Start();
            }
            //using内容结束时,释放资源,统计垃圾回收次数
            public void Dispose() {
                Console.WriteLine("{0},执行时间:{1}ms,垃圾回收次数:{2}",text,sw.ElapsedMilliseconds,GC.CollectionCount(0)-count);
            }

            //void IDisposable.Dispose()
            //{
            //    throw new NotImplementedException();
            //}
        }
        ///相当于进行垃圾回收重置操作,即先垃圾回收上一次遗留,并确保完成
        ///并重新开始垃圾回收
        private static void PrepareForOperation() {
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
        }
    }

    class MyFinalizeObject
    {
        // Make this number very large to cause the finalizer to
        // do more work.
        private const int maxIterations = 10000;

        ~MyFinalizeObject()
        {
            Console.WriteLine("Finalizing a MyFinalizeObject");

            // Do some work.
            for (int i = 0; i < maxIterations; i++)
            {
                // This method performs no operation on i, but prevents
                // the JIT compiler from optimizing away the code inside
                // the loop.
                /*此方法对i不执行任何操作,但阻止

JIT编译器从优化内部代码开始

循环。*/
                //阻止内存垃圾回收
                GC.KeepAlive(i);
            }
        }
    }


}

花了两三天的时间,将泛型方方面面的知识整理了一遍,主要参考《CLR via C#》,算是比较专业齐全的,

诚恳的说,如果希望能更多收获,提高自己写代码水平,没什么捷径,就是多看多写,多思考总结
比如这里封装,比较代码执行性能的的方法,统计时间和垃圾回收次数的代码。

这里只是个人学习笔记,一来个人能力有限,二来时间仓促,恐有谬误疏忽不足之处,唯有开放共同交流,才能更好的进步,欢迎提各位同仁,留言私信,提出建议交流。

比如第四个知识点:泛型缓存应用,博主就不甚清楚

总之,纸上得来终觉浅,绝知此事要躬行,一起努力吧!

你可能感兴趣的:(c#)