程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 由C++轉向C#需要注意的變化(三)

由C++轉向C#需要注意的變化(三)

編輯:C#入門知識

引言:每隔10年左右,編程人員就需要花費大量的時間和精力去學習新的編程技術。在80年代是Unix和C,90年代是Windows和C++,現在又輪到了微軟的.NETFramework和C#。盡管需要學習新的技術,但由此帶來的好處卻遠高於付出的勞動。幸運的是,使用C#和.NET進行的大多數工程的分析和設計與在C++和Windows中沒有本質的變化。在本篇文章中,我將介紹如何實現由C++到C#的飛躍。

  系列文章:[由C++轉向C#需要注意的變化(一)(二)(三)(四)]

  IEnumerable界面

  再回到上面的例子中。象在普通的數組中那樣,使用foreach-loop循環結構就能夠很好地打印ListBoxTest類中的字符串,通過在類中實現IEnumerable界面就能實現,這是由foreach-loop循環結構隱性地完成的。在任何支持枚舉和foreach-loop循環的類中都可以實現IEnumerable界面。

  IEnumerable界面只有一個方法GetEnumerator,其任務是返回一個特別的IEnumerator的實現。從語法的角度來看,Enumerable類能夠提供一個IEnumerator。


   Figure5ListBoxClass
  usingSystem;
  //簡化的ListBox控制
  publicclassListBoxTest
  {
  //用字符串初始化該ListBox
  publicListBoxTest(paramsstring[]initialStrings)
  {
  //為字符串分配空間
  myStrings=newString[256];
  //把字符串拷貝到構造器中
  foreach(stringsininitialStrings)
  {
  myStrings[myCtr++]=s;
  }
  }
  //在ListBox的末尾添加一個字符串
  publicvoidAdd(stringtheString)
  {
  myStrings[myCtr++]=theString;
  }
  publicstringthis[intindex]
  {
  get
  {
  if(index<0||index>=myStrings.Length)
  {
  //處理有問題的索引
  }
  returnmyStrings[index];
  }
  set
  {
  myStrings[index]=value;
  }
  }
  //返回有多少個字符串
  publicintGetNumEntries()
  {
  returnmyCtr;
  }
  privatestring[]myStrings;
  privateintmyCtr=0;
  }
  publicclassTester
  {

 staticvoidMain()
  {
  //創建一個新的列表並初始化
  ListBoxTestlbt=newListBoxTest("Hello","World");
  //添加一些新字符串
  lbt.Add("Who");
  lbt.Add("Is");
  lbt.Add("John");
  lbt.Add("Galt");
  stringsubst="Universe";
  lbt[1]=subst;
  //訪問所有的字符串
  for(inti=0;i  {
  Console.WriteLine("lbt[{0}]:{1}",i,lbt[i]);
  }
  }
  } 


  Enumerator必須實現IEnumerator方法,這可以直接通過一個容器類或一個獨立的類實現,後一種方法經常被選用,因為它可以將這一任務封裝在Enumerator類中,而不會使容器類顯得很混亂。我們將在上面代碼中的ListBoxTest中添加Enumerator類,由於Enumerator類是針對我們的容器類的(因為ListBoxEnumerator必須清楚ListBoxTest的許多情況),我們將使它在ListBoxTest中成為不公開的。在本例中,ListBoxTest被定義來完成IEnumerable界面,IEnumerable界面必須返回一個Enumerator。


   publicIEnumeratorGetEnumerator()
  {
  return(IEnumerator)newListBoxEnumerator(this);
  } 


  注意,方法將當前的ListBoxTest對象(this)傳遞給Enumerator,這將使Enumerator枚舉這一指定的ListBoxTest對象中的元素。

  實現這一類的Enumerator在這裡被實現為ListBoxEnumerator,它在ListBoxTest中被定義成一個私有類,這一工作是相當簡單的。

  被枚舉的ListBoxTest作為一個參數被傳遞給constructor,ListBoxTest被賦給變量myLBT,構造器還會將成員變量index設置為-1,表明對象的枚舉還沒有開始。


   publicListBoxEnumerator(ListBoxTesttheLB)
  {
  myLBT=theLB;
  index=-1;
  } 


  MoveNext方法對index進行加1的操作,然後確保沒有超過枚舉的對象的邊界。如果超過邊界了,就會返回false值,否則返回true值。


   publicboolMoveNext()
  {
  index++;
  if(index>=myLBT.myStrings.Length)
  returnfalse;
  else
  returntrue;
  } 


  Reset的作用僅僅是將index的值設置為-1。

  Current返回最近添加的字符串,這是一個任意的設定,在其他類中,Current可以有設計人員確定的意義。無論是如何設計的,每個進行枚舉的方法必須能夠返回當前的成員。


   publicobjectCurrent
  {
  get
  {
  return(myLBT[index]);
  }
  } 

對foreach循環結構的調用能夠獲取枚舉的方法,並用它處理數組中的每個成員。由於foreach循環結構將顯示每一個字符串,而無論我們是否添加了一個有意義的值,我們將myStrings的初始化改為8個條目,以保證顯示的易於處理。


   myStrings=newString[8]; 


  使用基本類庫

  為了更好地理解C#與C++的區別和解決問題方式的變化,我們先來看一個比較簡單的例子。我們將創建一個讀取文本文件的類,並在屏幕上顯示其內容。我將把它做成多線程程序,以便在從磁盤上讀取數據時還可以做其他的工作。

  在C++中,我們可能會創建一個讀文件的線程和另一個做其他工作的線程,這二個線程將各自獨立地運行,但可能會需要對它們進行同步。在C#中,我們也可以完成同樣的工作,由於.NET框架提供了功能強大的異步I/O機制,在編寫線程時,我們會節省不少的時間。

  異步I/O支持是內置在CLR中的,而且幾乎與使用正常的I/O流類一樣簡單。在程序的開始,我們首先通知編譯器,我們將在程序中使用許多名字空間中的對象:


   usingSystem;
  usingSystem.IO;
  usingSystem.Text; 


  在程序中包含System,並不會自動地包含其所有的子名字空間,必須使用using關健字明確地包含每個子名字空間。我們在例子中會用到I/O流類,因此需要包含System.IO名字空間,我們還需要System.Text名字空間支持字節流的ASCII編碼。

  由於.NET架構為完成了大部分的工作,編寫這一程序所需的步驟相當簡單。我們將用到Stream類的BeginRead方法,它提供異步I/O功能,將數據讀入到一個緩沖區中,當緩沖區可以處理時調用相應的處理程序。

  我們需要使用一個字節數組作為緩沖區和回叫方法的代理,並將這二者定義為驅動程序類的private成員變量。


   publicclassAsynchIOTester
  {
  privateStreaminputStream;
  privatebyte[]buffer;
  privateAsyncCallbackmyCallBack; 


  inputStream是一個Stream類型的變量,我們將對它調用BeginRead方法。代理與成員函數的指針非常相似。代理是C#的第一類元素。

  當緩沖區被磁盤上的文件填滿時,.NET將調用被代理的方法對數據進行處理。在等待讀取數據期間,我們可以讓計算機完成其他的工作。(在本例中是將1個整型變量由1增加到50000,但在實際的應用程序中,我們可以讓計算機與用戶進行交互或作其他有意義的工作。)

  本例中的代理被定義為AsyncCallback類型的過程,這是Stream的BeginRead方法所需要的。System空間中AsyncCallback類型代理的定義如下所示:


   publicdelegatevoidAsyncCallback(IAsyncResultar); 


  這一代理可以是與任何返回void類型值、將IAsyncResult界面作為參數的方法相關聯的。在該方法被調用時,CLR可以在運行時傳遞IAsyncResult界面對象作為參數。我們需要如下所示的形式定義該方法:


   voidOnCompletedRead(IAsyncResultasyncResult) 


  然後在構造器中與代理連接起來:


   AsynchIOTester()
  {
  ???
  myCallBack=newAsyncCallback(this.OnCompletedRead);
  } 


  上面的代碼將代理的實例賦給成員變量myCallback。下面是全部程序的詳細工作原理。在Main函數中,創建了一個類的實例,並讓它開始運行:


 

   publicstaticvoidMain()
  {
  AsynchIOTestertheApp=newAsynchIOTester();
  theApp.Run();
  } 


  new關健字能夠啟動構造器。在構造器中我們打開一個文件,並得到一個Stream對象。然後在緩沖中分配空間並與回調機制聯結起來。


   AsynchIOTester()
  {
  inputStream=File.OpenRead(@"C:MSDNfromCppToCS.txt");
  buffer=newbyte[BUFFER_SIZE];
  myCallBack=newAsyncCallback(this.OnCompletedRead);
  } 


  在Run方法中,我們調用了BeginRead,它將以異步的方式讀取文件。


   inputStream.BeginRead(
  buffer,//存放結果
  0,//偏移量
  buffer.Length,//緩沖區中有多少字節
  myCallBack,//回調代理
  null);//本地對象 


  這時,我們可以完成其他的工作。


   for(longi=0;i<50000;

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved