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
 {
//程序完成后一定会执行的操作
}
原文地址:https://www.cnblogs.com/praybb/p/7904793.html