C#高級編程筆記(11至16章)異步/託管/反射/異常

11.1.2LINQ語句

LINQ查詢表達式以from子句開始,以select或者group子句結束。在這兩個子句之間能夠跟零個或者多個from、let、where、join或者orderby子句。html

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擴展方法python

若是有類的源碼,繼承就能夠給對象添加方法。但若是沒有源代碼,則可使用擴展方法,它容許改變一個類,但不須要該類的源代碼。
擴展方法是靜態方法,它是類的一部分,但實際上沒有放在類的源代碼中。假定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.async

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

一、Invoke() 調用時,Invoke會阻止當前主線程的運行,等到 Invoke() 方法返回才繼續執行後面的代碼,表現出「同步」的概念。
二、BeginInvoke() 調用時,當前線程會啓用線程池中的某個線程來執行此方法,BeginInvoke不會阻止當前主線程的運行,而是等當前主線程作完事情以後再執行BeginInvoke中的代碼內容,表現出「異步」的概念。

IAsyncResult rtn = 委託變量.BeginInvoke(……); // 啓動異步調用
三、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\n",*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

一、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:\12\Some"); //在c:\12\Some查找程序集"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
 {
//程序完成後必定會執行的操做
}
相關文章
相關標籤/搜索