脚本宝典收集整理的这篇文章主要介绍了委托和泛型,脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。
委托类似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
public delegate Cloth Produce(in ISource _source)
函数的含义就是顾客给原材料,厂商生产衣服,但是厂商不能动顾客的原材料。顾客给的是什么,执行函数后还是原样。
out
public delegate void Produce(in ISource _source,out Cloth _cloth)
函数的含义就是顾客不仅给原材料,还会给一个衣服。至于是什么样的衣服,或者是根本就没有衣服,厂商不仅不能动原材料,还要产出衣服给out参数。
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.装箱与拆箱。
值类型与引用类型 C#和Java一样万物都是类,即使是值类型也是继承自ValueTyPE->Object。但是编译器会对继承自ValueType的类特殊处理。值类型储存在栈上,引用类型储存在堆上。值类型是一般意义的非面向对象的数据结构,仅仅是服务于计算。引用类型服务于整个项目工程。
装箱与拆箱
int i = 10;
object j = i;
Console.WriteLine(i + " " + j);
考虑上述语句:虽然输出值是一样的,但i是值类型,存于栈中;j是引用类型,存于堆中。 把值类型转化为引用类型的操作就是装箱,反正为拆箱。从栈到堆要重新申请地址填写元数据,等于就是又生成了一个变量,增大了性能开销。 为了解决这种浪费问题,可以通过构造函数、自定义函数传参。但是这样的话,针对不同类型的变量就要写许许多多函数。泛型就是用来解决代码重复问题,也是loc控制反转、di依赖注入思想的体现。
继承
public class Student<T> : Person<T>
和一般类的继承是一样的,但是泛型的继承要求T是相同的类。还有种指定父类泛型的继承:
public class Student<T1> : Person<T1,string>
注意泛型个数的变化。可以理解为每一种不同T的泛型都是不同的,独立的类。比如静态属性:
静态属性
Student<int>.i = 10;
Student<string>.i= 6;
Console.WriteLine(Student<int>.i);
互相独立无法影响。 C#中无法访问属性一样,通过实例访问静态属性,因为静态属性是属于整个类的。
默认值
public T name=default(T);
值类型为0,引用为null
返回值是泛型
public Person<T> GetPerson()
参数是泛型
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要相同。
泛型方法
public Person<T> GetPerson<T>()
{
var temp = new Person<T>();
return temp;
}
泛型方法的目的也是为了减少代码重用。不同的泛型类调用不同的方法
协变与抗变 首先在看协变与抗变之前先回顾类与子类:
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
以上是脚本宝典为你收集整理的委托和泛型全部内容,希望文章能够帮你解决委托和泛型所遇到的问题。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。