zoukankan      html  css  js  c++  java
  • C#高级编程笔记(11至16章)异步/托管/反射/异常

    11.1.2LINQ语句

    LINQ查询表达式以from子句开始,以select或者group子句结束。在这两个子句之间可以跟零个或者多个from、let、where、join或者orderby子句。

    static void LINQQuery()
        {
     //Formula1.GetChampions()返回一个列表,quer变量只是一个赋值语句,只有使用了foreach才会执行查询
          var query = from r in Formula1.GetChampions()  
                      where r.Country == "Brazil"
                      orderby r.Wins descending
                      select r;
          foreach (var r in query)
          {
            Console.WriteLine("{0:A}", r);
          }
        }

    11.1.3扩展方法

    如果有类的源码,继承就可以给对象添加方法。但如果没有源代码,则可以使用扩展方法,它允许改变一个类,但不需要该类的源代码。
    扩展方法是静态方法,它是类的一部分,但实际上没有放在类的源代码中。假定PhoneCusStruct类需要一个Add()方法,但不能修改源代码,就可以创建一个静态类,把Add()方法添加为一个静态方法

    public static class PhoneExtension
      {
        public static void Add(this PhoneCusStruct phoneCusStruct,string phone)
        {
        //
        }

    注意扩展方法的第一个参数是要扩展的类型,它放在this关键字的后面。这告诉编译器,这个方法是PhoneCusStruct类型的一部分。在这个例子中,PhoneCusStruct是要扩展的类型。在扩展方法中,可以访问所扩展类型的所有公有方法和属性。
      调用:PhoneCusStruct p =new PhoneCusStruct();
          p.Add();//即使方法是静态方法,也需要使用实例方法的语法。
    如果扩展方法与类中的某个方法同名,就不会调用扩展方法。类中已有的任何实例方法优先。

    编译器会转换LINQ查询,以调用方法而不是LINQ查询。LINQ为IEnumerable<T>接口提供了各种扩展方法(扩展方法在上面介绍到),以便用户在实现了该接口的任意集合上使用LINQ查询。
    定义LINQ扩展方法的一个类是System.Linq名称空间中的IEnumerable。只需要导入这个名称空间,就打开了这个类的扩展方法的作用域。下面是Where()扩展方法的实现代码:

    public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source,Func<TSource,bool> predicate)
            {
                foreach(TSource item in source)
                {
                    if(predicate(item))
                    {
                        yield return item;
                    }
                    
                }
            }

      因为Where()作为一个泛型方法,所以它可以用于包含在集合中的任意类型。实现了IEnumerable<T>接口的任意集合都支持它。

    相关链接

    其因相关使用在应用环境中再学习!这里先做了解

    12.动态语言扩展

    12.1 DRL (System.Dynamic与System.Runtime.ComplierServices)

    Dynamic Language Runtime动态语言允许添加动态语言,如Ruby和Python.

    12.2 dynamic类型

    dynamic的对象可以在运行期间改变其类型.其类型是有用的,但它是有代价的!

    dynamic dyn;
    dyn = 100;
    Console.WriteLine(dyn.GetType()); //输出System.int32
    Console.WriteLine(dyn);                  //输出100
    
     dyn = "This is a string";
    Console.WriteLine(dyn.GetType());      //输出System.String
    Console.WriteLine(dyn);                       //输出This is a string

    12.3包含DLR ScriptRuntime

    利用脚本完成工作,相关应用相对少,可请选读 因要了解python语言,暂时跳过

    相关使用

    13异步编程

    13.1

    1、Invoke() 调用时,Invoke会阻止当前主线程的运行,等到 Invoke() 方法返回才继续执行后面的代码,表现出“同步”的概念。
    2、BeginInvoke() 调用时,当前线程会启用线程池中的某个线程来执行此方法,BeginInvoke不会阻止当前主线程的运行,而是等当前主线程做完事情之后再执行BeginInvoke中的代码内容,表现出“异步”的概念。

    IAsyncResult rtn = 委托变量.BeginInvoke(……); // 启动异步调用
    3、EndInvoke() ,在想获取 BeginInvoke() 执行完毕后的结果时,调用此方法来获取。

    用于保存方法结果的变量=委托变量.EndInvoke(rtn); // 阻塞并等待异步调用结束

    相关的说明   关于EndInvoke()的示例

    13.3.1创建任务

    static string Greeting(string name) //Greeting同步方法
        {
          Console.WriteLine("运行时访问的线程是:{0}与任务是:{1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId);
    
          Thread.Sleep(3000);
          return string.Format("Hello, {0}", name);
        }
    static Task<string> GreetingAsync(string name) //异步方法GreetingAsync返回的是Task<string>
    {
       return Task.Run<string>(()=>
        {
         return Greeting(name);
         Console.WriteLine("running greetingasync in thread {0} and task {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId);
         });
    }

    13.3.2调用异步方法

    private async static void CallerWithAsync()
    {
        Console.WriteLine((await GreetingAsync("Stephanie")); //async修饰符只能用于返回Task或Void的方法
     }

    13.3.3延续任务

    ContinueWith方法定义了任务完成后就调用的代码(注:如任务清理工作可等)

    private static void CallerWithContinuationTask()
        {
          Console.WriteLine("CallerWithContinuationTask线程为 {0} 任务 {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId);
          var t1 = GreetingAsync("Stephanie");
          t1.ContinueWith(t =>
            {
              string result = t.Result;  // 访问任务返回的结果
              Console.WriteLine(result);
              Console.WriteLine("完成后的运行线程 {0} 任务 {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId);
            });
        }
    
    //输出为:
    //   CallerWithContinuationTask线程为 1 任务
    //   running greetingasync in thread 3 and task 1
    //   运行时访问的线程是:3与任务是:1
    //   Hello, Stephanie
    //   完成后的运行线程 4 任务 2

    13.3.4同步上下文 相关链接 相关链接2

    上下文简单理解为当时的环境即可,环境可以包括当时程序状态以及变量的状态,例如线程切换的时候在内核会发生上下文切换,这里的上下文就包括了当时寄存器的值,把寄存器的值都保存起来,等下次该线程又得到CPU时间的时候再恢复寄存器的值,这样线程才能正确的运行.

    //如果不加上下文,那么就是以对象为线程锁定区域,如果加上下文,那么就是以逻辑上下文为锁定区域    
        [Synchronization(SynchronizationAttribute.REQUIRED, true)] 
        class synchronizationClass : ContextBoundObject
        {
            public void Start()
            {
                MessageBox.Show(Thread.CurrentThread.Name);
            }
        }

    因为是使用SynchronizationAttribute来创建锁的,所以第一句[Synchronization(SynchronizationAttribute.REQUIRED, true)] 是必不可少的。

    又因为是为ContextBoundObject对象创建锁,所以对象必须是ContextBoundObject,故必须继承ContextBoundObject。

    两者缺一不可。测试:

    synchronizationClass myclass = new synchronizationClass();
    Thread thread = new Thread(new ThreadStart(myclass.Start));
    thread.Name = "thread1";
    Thread thread2 = new Thread(new ThreadStart(myclass.Start));
    thread2.Name = "thread2";
    thread.Start();
    thread2.Start();

    现象是thread1先弹框,点击确定后再弹thread2,原因就是整个对象都是一个锁,就是在thread1没处理完,thread2是无法进行操作的。
    所以呢,上下文同步域会将整一个上下文全部锁定,就是说整个类都成为了一个锁,在线程1未走出该类,线程2就无法进入该类。
    加入我把[Synchronization(SynchronizationAttribute.REQUIRED, true)]或者不继承ContextBoundObject发现此时的现象是thread1和thread2都会弹出框。
    这就是锁与不锁的区别了。

    13.3.5使用多个异步方法

    1.按顺序调用异步方法 (按顺序使用await)

    2.使用组合器

    Task<string> t1 = GreetingAsync("Stephanie");await Task.WhenAll(t1, t2);//所有提供的任务都已完成时,才会返回Tack

    Task.WhenAny()//在其中一个任何提供的任务已完成时,就会返回Tack

    13.3.6 转换异步模式

    转换为基于任务的异步模式  基于任务模式的异步的相关知识点

    private static async void ConvertingAsyncPattern()
     {
       string r = await Task<string>.Factory.FromAsync<string>(BeginGreeting, EndGreeting, "Angela", null);//创建一个任务,它表示符合异步编程模型模式的成对的开始和结束方法。
       Console.WriteLine(r);
     }
      /// <summary>
       /// 从同步方法中借助委拖,创建一个异步方法
       /// </summary>
     private static Func<string, string> greetingInvoker = Greeting;
       /// <summary>
       /// 异步模式
       /// </summary>
       /// <param name="name">异步模式名</param>
       /// <param name="callback">异步操作的状态</param>
       /// <param name="state"></param>
       /// <returns></returns>
     static IAsyncResult BeginGreeting(string name, AsyncCallback callback, object state) 
    {
     return greetingInvoker.BeginInvoke(name, callback, state);
    }
    
    static string EndGreeting(IAsyncResult ar)
    {
     return greetingInvoker.EndInvoke(ar);
    }

    13.4.1异步方法的异常处理

    static async Task ThrowAfter(int ms, string message)
    {
      await Task.Delay(ms); 
      throw new Exception(message);
    }
        private static async void HandleOneError()
    {
      try
      {
        await ThrowAfter(2000, "first");//如果不加入await的话 就无法捕捉异常!
      }
      catch (Exception ex)
      {
        Console.WriteLine("handled {0}", ex.Message);
      }
    }

    13.4.2使用AggregateException信息

    Task taskResult = null;
        try
          {
            Task t1 = ThrowAfter(2000, "first");
            Task t2 = ThrowAfter(1000, "second");
            await (taskResult = Task.WhenAll(t1, t2));
          }
          catch (Exception ex)
          {
           // 第一个任务的异常信息,只显示在所有等待
           Console.WriteLine("handled {0}", ex.Message);
            foreach (var ex1 in taskResult.Exception.InnerExceptions)
            {
              Console.WriteLine("inner exception {0} from task {1}", ex1.Message, ex1.Source);
            }
          }

    13.5取消

    相关链接

    private CancellationTokenSource cts = new CancellationTokenSource();
        private void OnCancel(object sender, RoutedEventArgs e)
        {
          if (cts != null)
            cts.Cancel();
        }

    13.5.2使用框架特性取消任务

    private async void OnTaskBasedAsyncPattern(object sender,RoutedEventArgs e)
    {
    cts =new CancellationTokenSourcs();
    try{
    foreach(var req in GetSearchRequests())
    var Client =new HttpClient();
    var response = await Client.GetAsync(req.Url, cts.Token);//用以异步操作的 HTTP 完成选项和取消标记发送 GET 请求到指定的 URI。
    string resp = await Response.Content.ReadAsStringAsync();
    }
    catch (OperationCanceledException ex)
    {
        MessageBox.Show(ex.Message);
    }
    }

    13.5.3取消自定义任务

    没测试!!跳过

    private async void test()
            {
                
                await Task.Run(() =>
                {
                    var images = req.Parse(resp);
                    foreach(var image in images)
                {
                        cts.Token.ThrowIfCancellationRequested();
                        searchInfo.list.add(image);
                    }
                }, cts.Token);
            }

    14内存管理与指针

    int类型为为4个字节,即占用4个指针位. double占8个字节

    14.2.值数据类型

    参考C的示例
    #include<stdio.h> 
    int *fun1(){ int a; return &a;} 
    int fun2(){ int b=6; } 
    int main(){ 
        int *p=fun1(); 
        fun2();
    printf("%d
    ",*p);}

    局部变量在函数调用完就会擦除(应该跟程序的联系),可是你使用局部变量时存放的是栈段,栈段的顺序是后进先出,而你刚好申请了相同大小的变量空间,系统直接就把那块空间又分配给你了,而里面的内容并没擦除。

    14.2.3 垃圾回收

    托管程序会自动更新地址,压缩堆形成一个连接的内存块

    GC是一个垃圾回收机制 它主要是回收 托管对象 而不会回收 非托管对象 就像你使用某些非托管数据库链接对象的时候 就需要手动关闭 这些需要手动关闭的对象就是非托管对象 而这个就不是在GC管理范围之内
    另外要说一下的是 GC这个东西很调皮 有时候GC的回收是没有固定时间的 随机的 所以 有时候我们需要手动关闭一些比较大的托管对象来提高性能

    14.3 释放非托管的资源

    14.3.2IDisposable接口

    在C#中,推荐使用System.IDisposable接口替代折构函数

    class ResouerceGobbler : IDisposable
        {
            public void Dispose()
            {
            }
        }

    ResouerceGobbler theInstance = new ResouerceGobbler(); //使用

    //程序
    theInstance.Dispose()  //释放

    如果处理过程中出现异常,没有释放,所以应该使用

    ResouerceGobbler theInstance = null;
                try
                {
                    theInstance = new ResouerceGobbler();
                  //程序
                }
                finally
                {
                    if (theInstance != null)
                    {
                        theInstance.Dispose();
                    }
                }

    以上代码有点混乱,所以有了下面的语法

    using(  ResouerceGobbler theInstance = new ResouerceGobbler())
    {
    //程序
    }

    close()是调用dispose()的方法实现的

    14.4用指针直接访问内存

    使用指针的主要原因

    1.向后兼容性

    调用本地WindowsAPI函数,可以使用DllLmport声明,以避免使用指针

    2.性能

    一. 用unsafe 关键字编写不安全的代码

    unasfe int GetSomeNumber(){} //表示这是一个不安全的方法! 也可以标记class或参数虚方法等,不能在局部变量本身标记为unsafe

    如果要使用不安全变量,需要在不安全的方法中声明和使用它

    VS可在项目属性窗口的Build选项中找到不安全代码的选项

    二.指针的语法(命名时前面是小写p)

    int* pWidth;    //*是在类型后面!!与变量无关 C++中是在变量上 如: int *pWidth ,要区分开

    &表示取地址 int* pX =&x //表示pX指向x

    3将指针强制转换为整数类型

    int x=10; int* pX,pY; pX = &x; pY =pX; * pY =20;   uint y =(uint)pX; int* pD = (int*) Y;

    4.指针类型之间的强制转换

    double* pDouble = (double*) pByte//pByte指针转换为double指针,不会得到一个有意义的值. (合法的代码)

    5.void指针

    int* pointerToInt; void* pointerToVoid; pointerToVoid = (void*)pointerToInt;//很少用,主要用于调用需要void*参数API函数

    6.指针算术的运算 +、-、+=、-=、++、--

    int* pInt=&int变量; pInt += 1 //不允许对void指针运算,注意byte与char其总字节数不是4的倍数,不能使用P+X*(sizeof(T))算法

    7sizeof运算符

    int x =sizeof(double) //返double类型占用的字节数,注意不能用于计算类

    8.结构指针:指针成员访问运算符

    struct MyStruct
    {public log X;
    public float F;
    }
    MyStruct* pStruct;                //定义一个指针
    MyStruct Struct = new MyStruct(); //初始化
    pStruct = &Struct;                //通过指针访问结构成员
    (*pStruct).X = 4;                 
    (*pStruct).Y =3.4f;

    上述代码改写为

    pStruct->X = 4;
    pStruct->Y = 3.4f;

    类成员指针

    对象存储在堆上,垃圾回收过程会变动,所以要使用fixed,语法如下

    MyClass myObject =new MyClass();
    Fixed (long* pX = &(myObject.X))
    Fixed (float* pF = &(myObject.F))
    {
        //程序
    }
    //类型相同时可以放在一条fixed中 fixed(long* pX = &(myObject.X),pF = &(myObject.F))如果不同阶段固定指针,可以嵌套fixed块

    14.4指针示例

    使用{0:X}格式输出十六进制

    15 反射

    15.2.1编写自定义特性

    下面为自定义元素时

    [FieldNameAttribute("SocialSecurityNumber")]
    public string SocialSecurityNumber
    {
    get{
    //ect

    1、AttributeUsage特性

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
     //AllowMultiple = true 允许它多次应用到同一项上 
     //Inherited = false如果该属性可以由派生类和重写成员继承,则为 true;否则为 false。 默认值为 true
        public class LastModifiedAttribute : Attribute
        {
             public LastModifiedAttribute(string dateModified, string changes)
            {
               //程序
            }
        }
    [LastModified("14 Feb 2010", "IEnumerable interface implemented So Vector can now be treated as a collection")]

    15.3反射

    15.3.1 System.type类

    属性

    Type intType=typeof(int); //Type的属性 name, fullname, Namepace命名空间, BaseType基类型 isClass是否为类

    方法

    Type intType = typeof(int); 
      MethodInfo[] methods = intType.GetMethods();  //取得该类型的法方
       foreach (var test in methods)
       {
          Console.WriteLine(test);
       }

    15.3.3 Assembly类 System.Reflection

    加载

    Assembly theAssembly = Assembly.Load("VectorClass"); //查找程序集"VectorClass"
    Assembly theAssembly = Assembly.LoadFrom(@"c:12Some"); //在c:12Some查找程序集"VectorClass"

    1,获取程序集中定义的类型的详细信息

    ype[] types = theAssembly.GetTypes();

    2获取自定义特性的详细信息

    Attribute supportsAttribute = Attribute.GetCustomAttribute(theAssembly, typeof (SupportsWhatsNewAttribute)); //获取程序集的特性

    关于使用

    Type T2 = typeof(TClass);
    var Mets = T2.GetMembers();//获取所有公共成员(返回值是MemberInfo类型集合)
    foreach (var m in Mets)
    {
        if (m.Name=="Equals")
        {
            Console.WriteLine("" + m.MemberType.ToString() + "】:" + m.Name);
            // m.MemberType 是成员类型
    
            // m.DeclaringType;//获取申明该成员的类
            // m.ReflectedType;//获取用于获取 MemberInfo 的此实例的类对象。 
    
        } 
    }

    相关的附加链接

    16 错误与异常

    关于异常类的介绍

    try
     {
         throw new Exception("ft");
     }
     catch (OverflowException ex)
     { }
     catch (Exception ex)
     { }
     finally
     {
    //程序完成后一定会执行的操作
    }
  • 相关阅读:
    今日总结
    今日总结
    今日总结
    k8s controller
    深入k8s:Informer使用及其源码分析
    理解 K8S 的设计精髓之 List-Watch机制和Informer模块
    Unix domain socket 简介
    Linux网络编程——端口复用(多个套接字绑定同一个端口)
    DPVS Tutorial
    dpvs route RTF_KNI
  • 原文地址:https://www.cnblogs.com/praybb/p/7904793.html
Copyright © 2011-2022 走看看