委托和泛型

发布时间:2022-07-04 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了委托和泛型脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

委托

委托类似C++的函数指针,但是函数指针不安全。C#中的委托就是一个新类,每次定义的时候都等于声明一个类。可以这么理解:委托类中储存函数元数据(返回值,参数,函数名),初始化的过程就是给函数具体的内容(就是存的内容是函数指针)。

  • 定义和初始化委托

      public delegate string GetString();
      class PRogram
      {
      	static void Main(string[] args)
      	{
      		VAR a = 10;
      		GetString getString = new GetString(a.ToString);
      		Console.WrITeLine(getString());
      	}
      }
    

调用实例方法时,可以调用实例的属性。

  • 匿名委托 委托中需要储存的有返回值和参数,考虑用泛型: Action<T>void,返回值由T来定 Fuction<T>eg:Fuction<int,int,bool>最后一个参数为返回值
  • 参数修饰符 in out ref 假设一个顾客要衣物工厂生产衣服
  1. in

     public delegate Cloth Produce(in ISource _source)
    

    函数的含义就是顾客给原材料,厂商生产衣服,但是厂商不能动顾客的原材料。顾客给的是什么,执行函数后还是原样。

  2. out

     public delegate void Produce(in ISource _source,out Cloth _cloth)
    

    函数的含义就是顾客不仅给原材料,还会给一个衣服。至于是什么样的衣服,或者是根本就没有衣服,厂商不仅不能动原材料,还要产出衣服给out参数。

  3. ref

     public delegate void Produce(in ISource _source,ref ISource _otherSource,out Cloth _cloth)
    

    函数的含义就是顾客给两种原材料,in的不能动,ref的可以修改,返回Cloth

  • 多播委托 委托重构了+、+=、-、-=。但是调用函数指针的顺序却没有定,且一个函数抛出异常整个迭代过程都会停止。

      GetString getString1=()=>Console.WriteLine("nihao");
      GetString getString2 = () => Console.WriteLine("woshi");
      GetString getString3 = () => Console.WriteLine("robot");
      GetString getString = getString1 + getString2 + getString3;
      getString();
    

    可以用Delegate类中的GetInvocationList()

      Delegate[] delegates = getString.GetInvocationList();
      foreach (GetString i in delegates)
      {
      	try
      	{
      		i();
      	}
      	catch (Exception e)
      	{
      		Console.WriteLine("wrong");
      	}
      }
    

泛型

泛型没什么好说的,首先要了解两个概念:1.值类型与引用类型。2.装箱与拆箱。

  1. 值类型与引用类型 C#和Java一样万物都是类,即使是值类型也是继承自ValueTyPE->Object。但是编译器会对继承自ValueType的类特殊处理。值类型储存在栈上,引用类型储存在堆上。值类型是一般意义的非面向对象的数据结构,仅仅是服务于计算。引用类型服务于整个项目工程。

  2. 装箱与拆箱

     int i = 10;
     object j = i;
     Console.WriteLine(i + " " + j);
    

    考虑上述语句:虽然输出值是一样的,但i是值类型,存于栈中;j是引用类型,存于堆中。 把值类型转化为引用类型的操作就是装箱,反正为拆箱。从栈到堆要重新申请地址填写元数据,等于就是又生成了一个变量,增大了性能开销。 为了解决这种浪费问题,可以通过构造函数、自定义函数传参。但是这样的话,针对不同类型的变量就要写许许多多函数。泛型就是用来解决代码重复问题,也是loc控制反转、di依赖注入思想的体现。

  • 泛型类
  1. 继承

     public class Student<T> : Person<T>
    

    和一般类的继承是一样的,但是泛型的继承要求T是相同的类。还有种指定父类泛型的继承:

     public class Student<T1> : Person<T1,string>
    

    注意泛型个数的变化。可以理解为每一种不同T的泛型都是不同的,独立的类。比如静态属性

  2. 静态属性

     Student<int>.i = 10;
     Student<string>.i= 6;
     Console.WriteLine(Student<int>.i);
    

    互相独立无法影响。 C#中无法访问属性一样,通过实例访问静态属性,因为静态属性是属于整个类的。

  3. 默认值

     public T name=default(T);
    

    值类型为0,引用为null

  • 泛型方法 前两种准确来说并不是泛型方法
  1. 返回值是泛型

     public Person<T> GetPerson()
    
  2. 参数是泛型

     public class Student<T> : Person<T>
     {
     	static int j;
     	public Person<T> GetPerson(T a)
     	{
     		var temp = new Person<T>();
     		temp.name=a;
     		return temp;
     	}
     }
    

    还是一个原则T要相同。

  3. 泛型方法

     public Person<T> GetPerson<T>()
     {
         var temp = new Person<T>();
         return temp;
     }
    

    泛型方法的目的也是为了减少代码重用。不同的泛型类调用不同的方法

  • 泛型接口
  1. 协变与抗变 首先在看协变与抗变之前先回顾类与子类:

    Student<string> s = new Student<string>();
    Person<string> p = s;
    
    Person<string> i = new Person<string>();
    Student<string> j = i;
    

    前一种可以编译通过,因为可以把子类的地址赋给父类的变量。但反过来就不可以了。这就是一种简单的协变与抗变。因为子类是从父类派生的。 方法也有协变与抗变:方法的参数是协变的,可以给父类参数赋子类对象的值,这也是依赖注入的实现方式。方法的返回值是抗变的,返回值最好是返回精确的类型。输入可以不精确,但是输出一定要确定。

     public interface IMyInterface<out T>
    

    这样定义的泛型类就可以对参数协变 public interface IMyInterface 这样的

  • 泛型结构 最常用的泛型结构就是可空类型Nullable

脚本宝典总结

以上是脚本宝典为你收集整理的委托和泛型全部内容,希望文章能够帮你解决委托和泛型所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。