C#知识要点整理(12月份整理)——结构类、泛型、委托和事件

一、结构与类

1、类:引用类型,存储在堆heap中,class; 堆:值类型,存储在栈stack中,struct
2、C#成员可访问行修饰有 public protected,internal
3、何时使用引用传递?ref?因为效率较高,面对复杂数据结构时采用
4、out参数 不初始化引用传入参数
function a(out  int x){
    x=12;
    return x;
}
int b;
a(out b);

此时b为12
与ref不同,ref传入需要初始化
5、静态构造函数:用于初始化类中静态字段和属性  再.net运行库调用, 加载时调用,无法保证先后
6、readonly字段 只能在构造函数声明
7、构造函数初始器:提供另一个够构造函数调用
public car (string description):this(description ,4));
public car(string description,int a);
8、C#对象 new出来后一般都为强引用,可以使用weakReference设置为弱引用,当GC垃圾回收期运行时进行对象的回收,因此使用时需要用isAlive判断是否存在
9、C# 与java不同,没有私有private继承
10、C#与Java不通,默认不是virtual虚函数,java默认为可以重写的虚函数
11、seal密封类-》不能集成 密封函数-》不能重写
12、default<T>可以将泛型类型指定为默认值 int为0 ,string 为空。。。
13、协变 泛型的传入参数可以传派生类 抗变返回类型
IDisplay<Shape>
IDisplay<Rectangle>
泛型接口定义In时,输入只能为T  为抗变,输出可以转化为基类
泛型接口定义为Out时,返回类型只能为T,传入可以传派生类为协变

二、泛型、数组、运算符转化

1、泛型结构:可空类型 ? 表示可空类型是一种典型的泛型结构,int? x1

可空与非空转化

int ?x1;
...
int y1=x1??0 //为空则为0

2、数组 为引用类型在堆上,事先不知道元素个数的话建议使用集合

3、不知道数组类型时,可以使用createInstance来创建

4、使用sort需要实现IComparable接口,接口只有一个compare方法

5、arr.clone方法 

①值类型:复制所有值

②引用类型:复制引用

6、foreach使用IEnumerator迭代集合中元素,接口主要有一个current表示当前位置,moveNext()移到下一个

C#把foreach解析为IEnumeable接口的方法和属性

获得IEnumerator的方法:

IEnumerator <person>  enumerator = persons.GetEnumrator()//获得枚举器
yield return 返回->移动 实现了一个枚举器

foreach默认使用GetENumeartor()等价于

foreach(var title in titles.getEnumerator())


7、结构比较 IStructuralEqutable, IStructComparable, 前者用于比较内容,后者用于进行排序

Equals(Object o ,IEquality e)
e实现IEqualityComparer<T>接口
(person ) as IStructuralEqutable.Equals(person2,EqualityConparer<Person> Default)

8、c#默认unchecked禁止溢出检查,可以使用checked代码块进行溢出检查

9、as 引用类型显示转换,如果不兼容 返回null

10、sizeof确定栈中需要长度 (单位字节)  int 为4

11、可空类型比较中如果有一个为null就为false

12、int强制转换成char时,转化为ASCII码为int的字符

13、装箱、拆箱 :把值类型转换为引用类型为装箱,创建引用类型的箱子

14、比较引用类型的4中方法

①、ReferenceEquals() 是否引用一个实例,Object的静态方法,值类型返回false null=null

②、Equals 静态 不必处理null

③、Equals动态 需要处理null,自定义

④、== 可以重载 默认与①相同

15、C#支持运算符重载,java要写函数才行

operator关键字告诉编译器是一个重载函数

public static vector operator +(vector rhs,vector rhs)

public static为要求的参数

重载==必须重载!=否则编译错误,还需重载Equals和GetHashCode()


16、自定义类型转换 implicit隐式  exolicit显式
17、类强制转换 ①、不能有派生关系 ②、只能在目标内部丁意思

三、委托、lambda表达式和事件

1、委托与函数指针的区别:
C++中函数指针是一个指向内存位置的指针,不是类型安全的,无法判断指向什么,.net委托是类型安全的类,定义了返回类型和参数类型,委托类能定义对多个方法的引用。
2、lambda表达式:与委托直接相关,用lambda表达式实现委托引用

委托:

1、给方法传递另一个方法作为参数
2、c与C++是通过提取函数地址,作为参数传递它。C没有类型安全,可以把任何函数传递给需要函数指针的方法,,net必须把方法细节封装到一个对象中,即委托中,委托是特殊类型的对象,包含一个或多个方法的地址
3、委托的声明
①定义委托②创建实例
delegate void IntMethodInvoker(int x);

定义时必须给出签名以及返回类型

类有类和实例,委托的实例也称为委托
4、调用委托圆括号方法与调用委托的Invoke()方法是一样的,firstStringMethod()与firstStringMethod.Invoke()相同
5、委托推断 : 只需要委托实例,就可以传送地址名称
GetAString  a = x.tostring
GetAString a = new GetAString(x.tostring)
6、委托是为了什么?目前的理解是为了传递函数,函数作参数,定义委托后,可以把函数当做变量使用,传入参数之后,在方法内进行调用
7、Action<T>  void返回类型的方法,Action<in T1,in T2...>传入参数
8、Func<T> 允许调用带返回类型的方法,Func<in T1,inT2....Out Tres>
9、冒泡排序适合一小组数字
委托的冒泡排序
static public void Sort<T> (Ilist<T> sortArray,Func<T,T,bool> compaison)

10、多播委托
委托包含多个方法。按照顺序连续调用,签名必须返回void,不然只能得到最后一个的返回结果
Action<double> operation 1 = fun1;
Action<double> operation 2 = fun2;
Action<double> opearyions = fun1+fun2;

Action<double> operations = fun1;
operations+=fun2
本质是派生自MulticastDelegate的类,把多个方法调用链接为一个列表
Problem:①、方法链的顺序并未正式定义——避免编写依赖于特定顺序调用方法的代码
                 ②、一个方法抛出异常,整个迭代都停止——Delegate的GetInvocationLis()方法返回一个Delegate数组
            Action d1 = fun1;
            d1+ = fun2;
            Delegate[] delegates = d1.GetInvocationList();
            foreach(Action d in delegates){
                try{
                    d();
                }
                catch(Exception)
                {
                ...
                }
            }
此时就算报错也会继续迭代
                
11、匿名方法:把代码传递给委托,而不是方法  Tips:①可以使用方法级的参数,②不能使用跳转语句break,goto,continue跳转出匿名方法,也不能跳转进去②不能访问不安全的代码,不能访问ref和out 的参数,3.0开始使用lambda表达式替代匿名方法
Func<string,string> a = delegate(string a ){...}
12、Lambda表达式:
param为传入参数,右侧为实现代码
参数:
①一个参数 ,写出参数名
Func<string,string> lambda = param=>
  {
       ....
  }
②多个参数
Func<double,double,double> twoparams = (double x,double y) =>x*y
最好为参数加上类型,如果只有条语句,可以不需要{}和return,编译器自动加return

闭包
lambda表达式可以访问块外部的变量称为闭包
lambda表达式创建一个匿名类,有一个构造函数传递外部变量,

使用foreach语句的闭包,C#5.0改变,
5.0之前使用的是外部变量,是在调用时,而不是迭代时获得val变量的值(就是第一次循环之后val为30,因为没有传入局部变量)需要定义个局部变量传入到lambda表达式中
5.0后不需要了foreach创建while循环式,会创建一个局部循环变量
var values = new list<int>() {10,20,30};
var funs = new list<Func<int>>();
foreach(var val in values){
  funs.Add(()=>val);
}
foreach(var f in funs){
 Console.WriteLine((f()));
}

5.0前输出3次30,5.0之后输出10,20,30

事件



事件为委托提供发布/订阅机制

class Program
    {
        static void Main(string[] args)
        {
             var dealer = new Dealer();
             var michael = new Consumer("michal");
             dealer.NewInfo += michael.NewInfoIsHere;
            //也可以通过-=取消订阅

        }
    }
 /// <summary>
 /// 
 /// </summary>
public class InfoEventArgs : EventArgs 
{
    public InfoEventArgs(string car)
    {
      this.info = info;
    }
     public string info { get;private set }
}
public class Dealer{
    public event EventHandler<InfoEventArgs> NewInfo; 
    //定义事件 EventHandler<TEventArgs>定义一个处理程序,返回void 带2个参数 ,第一个参数是对象(发送者),第二个T提供相关信息约束继承自EventArgs
    //public delegate void EventHandler<TEventArgs>(object sender,TEventArgs e) where TEventArgs:EventArgs  长标记表示。
    public void InfoNew(string info)
    {
       RaiseNewInfo(info);
    }
    protected virtual void RaiseNewInfo(string info)
    {
        EventHandler<InfoEventArgs> newINFO = NewInfo;
        if(newINFO!=null){
            
            newINFO(this,new InfoEventArgs(info));//这其实是一个委托=>michal.NeWInfoIsHere(this,new InfoEventArgs(info));
        }
    }
}
public class Consumer{
    private string name;
    public Consumer(string name ){
        this.name = name;
    }
    public void NewInfoIsHere(object sender, InfoEventArgs e)
    {
        Console.WriteLine("{0} : car {1} is new",name ,e.info);
    
    }
}

在发布者类中定义事件(本质是一个带2个参数的委托),通过eventArgs传递参数
在订阅者类中编写符合委托的方法,并且与发布者类事件绑定实现订阅
①发布者类事件发生(某个方法调用)->②发布者类调用事件绑定的委托(委托通过+=绑定了订阅者的事件)  期间发布者类new一个实现eventArgs接口的类传递参数。


弱事件:WeakEventManager 存在的理由:当侦听器不在直接引用,发布程序仍会保存一个引用,因此GC不能情况侦听器占用的内存。一种方法是确保对事件取消订阅,另外一种就是WeakEventManager

需要创建一个派生自WeakEventManager 的类作为弱事件管理器来管理发布程序和侦听器的连接
Addlistener与removelistemer实现了侦听器的添加删除
startlistening和stoplistening添加第一个时以及删除最后一个时会调用
侦听器实现IWeakEventListener借楼,实现ReceiveWeakEvent方法,触发事件时,弱事件管理器调用这个方法
public class WeakInfoEventManager:WeakEventManager{
    /// <summary>
    ///实现弱事件管理器类的单例
    /// </summary>
   
    public static void Addlistener(object source,IWeakEventListener listener)
    {
        CurrentManager.ProtectedAddListener(source,listener);
    }
      public static void Removelistener(object source,IWeakEventListener listener)
    {
        CurrentManager.ProtectedRemoveListener(source,listener);
    }
     public static WeakEventManager CurrentManager{
        get{
            var manager = GetCurrentManager(typeof(WeakInfoEventManager)) as WeakInfoEventManager;
            if(manager == null)
            {
                manager = new WeakInfoEventManager();
                SetCurrentManager(typeof(WeakInfoEventManager),manager);
            }
            return manager;
        }
    }
    /// <summary>
    /// 静态方法连接发布程序
    /// </summary>
    /// <param name="source"></param>
    protected override void  StartListening(object source)
    {
        (source as Dealer).NewInfo += Deal_NewInfo;
 	
    }
    void Deal_NewInfo(object  sender,InfoEventArgs e){
        DeliverEvent(sender,e);
    }
    protected override void  StopListening(object source)
    {
 	(source as Dealer).NewInfo -= Deal_NewInfo;
    }

}

public class Consumer:IWeakEventListener{
    private string name;
    public Consumer(string name ){
        this.name = name;
    }
    public void NewInfoIsHere(object sender, InfoEventArgs e)
    {
        Console.WriteLine("{0} : car {1} is new",name ,e.info);
    
    }
    bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e) {
        NewInfoIsHere(sender, e as InfoEventArgs);
        return true;
    }
}

.net4.5 实现弱事件管理器泛型
WeakEventManager<TEventSource,TEventArgs>派生自基类WeakEventManager,不需要为每个事件实现自定义弱事件管理器,不需要侦听器实现接口IWeakEventsListener,只需要订阅和取消事件
            WeakEventManager<Dealer, InfoEventArgs>.AddHandler(dealer, "(NewInfo)事件名称", michael.NewInfoIsHere);
             WeakEventManager<Dealer, InfoEventArgs>.RemoveHandler(dealer, "(NewInfo)事件名称", michael.NewInfoIsHere);

我们会在开发Windows应用程序时大量使用委托和时间来监控应用程序执行时出现的Windows消息方式,在设计大型应用时可以减少依赖性和层的耦合,开发可重用的组件



  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值