日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

用.NET Core实现装饰模式和.NET Core的Stream简介

發布時間:2023/12/4 asp.net 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 用.NET Core实现装饰模式和.NET Core的Stream简介 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

該文章綜合了幾本書的內容.

某咖啡店項目的解決方案

某咖啡店供應咖啡, 客戶買咖啡的時候可以添加若干調味料, 最后要求算出總價錢.

Beverage是所有咖啡飲料的抽象類, 里面的cost方法是抽象的. description變量在每個子類里面都需要設置(表示對咖啡的描述).

每個子類實現cost方法, 表示咖啡的價格.

除了這些類之外, 還有調味品:

問題是調味品太多了, 如果使用繼承來做的話, 各種組合簡直是類的爆炸.

而且還有其他的問題, 如果牛奶的價格上漲了怎么辦? 如果再加一種焦糖調料呢?

另一種解決方案

父類里面有調味料的變量(bool), 并且在父類里面直接實現cost方法(通過是否有某種調味料來計算價格).

子類override父類的cost方法, 但是也調用父類的cost方法, 這樣就可以把子類這個咖啡的價格和父類里計算出來的調味料的價格加到一起算出最終的價格了.

下面就是:

看起來不錯, 那么, 問題來了:

  • 調味料價格變化的話就不得不修改現有代碼了

  • 如果有新的調味料那么久必須在父類里面添加新的方法, 并且修改cost方法了.

  • 可能某些調味料根本不適用于某些咖啡

  • 如果某個客戶想要兩個摩卡(調味料)怎么辦?

設計原則

類應該對擴展開放 而對修改關閉.

裝飾模式

使用裝飾模式, 我們可以購買一個咖啡, 并且在運行時使用調味料對它進行裝飾.

大約步驟如下:

  • 買某種咖啡

  • 使用mocha調味料裝飾它

  • 使用whip調味料裝飾它

  • 調用cost方法, 并且使用委托來計算調味料的總價格

  • ?

    ?

    到目前我知道了這些:

    • 裝飾器的父類和它所要裝飾的對象的父類是一樣的

    • 可以使用多個裝飾器來裝飾某對象

    • 既然裝飾器和被裝飾對象的父類是一樣的, 那傳遞的時候就傳遞被裝飾過的對象就好了.

    • 裝飾器會在委托給它要裝飾的對象之前和/或之后添加自己的行為以便來完成余下的工作.

    • 對象可以在任意時刻被裝飾, 所以可以在運行時使用任意多個裝飾器對對象進行裝飾.

    裝飾模式定義

    ?動態的對某個對象進行擴展(附加額外的職責), 裝飾器是除了繼承之外的另外一種為對象擴展功能的方法.

    下面看看該模式的類圖:

    重新設計

    這個就很好理解了, 父類都是Beverage(飲料), 左邊是四種具體實現的咖啡, 右邊上面是裝飾器的父類, 下面是具體的裝飾器(調味料).

    這里需要注意的是, 裝飾器和咖啡都繼承于同一個父類只是因為需要它們的類型匹配而已, 并不是要繼承行為.

    .NET Core 代碼實現

    Beverage:

    namespace DecoratorPattern.Core

    {

    ? ? public abstract class Beverage?

    ? ? {

    ? ? ? ? public virtual string Description { get; protected set; } = "Unknown Beverage";

    ? ? ? ??

    ? ? ? ? public abstract double Cost();

    ? ? }

    }

    CondimentDecorator:

    namespace DecoratorPattern.Core

    {

    ? ? public abstract class CondimentDecorator : Beverage

    ? ? {

    ? ? ? ? public abstract override string Description { get; }

    ? ? }

    }

    Espresso 濃咖啡:

    using DecoratorPattern.Core;


    namespace DecoratorPattern.Coffee

    {

    ? ? public class Espresso : Beverage

    ? ? {

    ? ? ? ? public Espresso()

    ? ? ? ? {

    ? ? ? ? ? ? Description = "Espresso";

    ? ? ? ? }

    ? ? ? ? public override double Cost()

    ? ? ? ? {

    ? ? ? ? ? ? return 1.99;

    ? ? ? ? }

    ? ? }

    }

    HouseBlend:

    using DecoratorPattern.Core;


    namespace DecoratorPattern.Coffee

    {

    ? ? public class HouseBlend : Beverage

    ? ? {

    ? ? ? ? public HouseBlend()

    ? ? ? ? {

    ? ? ? ? ? ? Description = "HouseBlend";

    ? ? ? ? }


    ? ? ? ? public override double Cost()

    ? ? ? ? {

    ? ? ? ? ? ? return .89;

    ? ? ? ? }

    ? ? }

    }

    Mocha:


    using DecoratorPattern.Core;


    namespace DecoratorPattern.Condiments

    {

    ? ? public class Mocha : CondimentDecorator

    ? ? {

    ? ? ? ? private readonly Beverage beverage;


    ? ? ? ? public Mocha(Beverage beverage) => this.beverage = beverage;


    ? ? ? ? public override string Description => $"{beverage.Description}, Mocha";


    ? ? ? ? public override double Cost()

    ? ? ? ? {

    ? ? ? ? ? ? return .20 + beverage.Cost();

    ? ? ? ? }

    ? ? }

    }

    Whip:

    using DecoratorPattern.Core;


    namespace DecoratorPattern.Condiments

    {

    ? ? public class Whip : CondimentDecorator

    ? ? {

    ? ? ? ? private readonly Beverage beverage;


    ? ? ? ? public Whip(Beverage beverage) => this.beverage = beverage;


    ? ? ? ? public override string Description => $"{beverage.Description}, Whip";


    ? ? ? ? public override double Cost()

    ? ? ? ? {

    ? ? ? ? ? ? return .15 + beverage.Cost();

    ? ? ? ? }

    ? ? }

    }

    Program:

    using System;

    using DecoratorPattern.Coffee;

    using DecoratorPattern.Condiments;

    using DecoratorPattern.Core;


    namespace DecoratorPattern

    {

    ? ? class Program

    ? ? {

    ? ? ? ? static void Main(string[] args)

    ? ? ? ? {

    ? ? ? ? ? ? var beverage = new Espresso();

    ? ? ? ? ? ? Console.WriteLine($"{beverage.Description} $ {beverage.Cost()}");


    ? ? ? ? ? ? Beverage beverage2 = new HouseBlend();

    ? ? ? ? ? ? beverage2 = new Mocha(beverage2);

    ? ? ? ? ? ? beverage2 = new Mocha(beverage2);

    ? ? ? ? ? ? beverage2 = new Whip(beverage2);

    ? ? ? ? ? ? Console.WriteLine($"{beverage2.Description} $ {beverage2.Cost()}");

    ? ? ? ??

    ? ? ? ? }

    ? ? }

    }


    運行結果:

    ?

    .NET Core里面的裝飾模式例子: Streams 和 I/O

    首先需要知道, System.IO命名空間是低級I/O功能的大本營.

    Stream的結構

    .NET Core里面的Stream主要是三個概念: 存儲(backing stores 我不知道怎么翻譯比較好),?裝飾器, 適配器.

    backing stores是讓輸入和輸出發揮作用的端點, 例如文件或者網絡連接. 就是下面任意一點或兩點:

    • 一個源, 從它這里字節可以被順序的讀取

    • 一個目的地, 字節可以被連續的寫入.

    程序員可以通過Stream類來發揮backing store的作用. Stream類有一套方法, 可以進行讀取, 寫入, 定位等操作. 個數組不同的是, 數組是把所有的數據都一同放在了內存里, 而stream則是順序的/連續的處理數據, 要么是一次處理一個字節, 要么是一次處理特定大小(不能太大, 可管理的范圍內)的數據.

    于是, stream可以用比較小的固定大小的內存來處理無論多大的backing store.

    中間的那部分就是裝飾器Stream. 它符合裝飾模式.

    從圖中可以看到, Stream又分為兩部分:

    • Backing Store Streams: 硬連接到特定類型的backing store, 例如FileStream和NetworkStream

    • Decorator Streams 裝飾器Stream: 使用某種方式把數據進行了轉化, 例如DeflateStream和CryptoStream.

    裝飾器Stream有如下結構性的優點(參考裝飾模式):

    • 無需讓backing store stream去實現例如壓縮, 加密等功能.

    • 裝飾的時候接口(interface)并沒有變化

    • 可以在運行時進行裝飾

    • 可以串聯裝飾(先后進行多個裝飾)

    backing store和裝飾器stream都是按字節進行處理的. 盡管這很靈活和高效, 但是程序一般還是采用更高級別的處理方式例如文字或者xml.

    適配器通過使用特殊化的方法把類里面的stream進行包裝成特殊的格式. 這就彌合了上述的間隔.

    例如 text reader有一個ReadLine方法, XML writer又WriteAttributes方法.

    注意: 適配器包裝了stream, 這點和裝飾器一樣, 但是不一樣的是, 適配器本身并不是stream, 它一般會把所有針對字節的方法都隱藏起來. 所以本文就不介紹適配器了.

    總結一下:

    backing store stream 提供原始數據, 裝飾器stream提供透明的轉換(例如加密); 適配器提供方法來處理高級別的類型例如字符串和xml.

    想要連成串的話, 秩序把對象傳遞到另一個對象的構造函數里.

    使用Stream

    Stream抽象類是所有Stream的基類.

    它的方法和屬性主要分三類基本操作: 讀, 寫, 尋址(Seek); 和管理操作: 關閉(close), 沖(flush)和設定超時:

    這些方法都有異步的版本, 加async, 返回Task即可.

    一個例子:

    using System;

    using System.IO;


    namespace Test

    {

    ? ? class Program

    ? ? {

    ? ? ? ? static void Main(string[] args)

    ? ? ? ? {

    ? ? ? ? ? ? // 在當前目錄創建按一個 test.txt 文件

    ? ? ? ? ? ? using (Stream s = new FileStream("test.txt", FileMode.Create))

    ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? Console.WriteLine(s.CanRead); // True

    ? ? ? ? ? ? ? ? Console.WriteLine(s.CanWrite); // True

    ? ? ? ? ? ? ? ? Console.WriteLine(s.CanSeek); // True

    ? ? ? ? ? ? ? ? s.WriteByte(101);

    ? ? ? ? ? ? ? ? s.WriteByte(102);

    ? ? ? ? ? ? ? ? byte[] block = { 1, 2, 3, 4, 5 };

    ? ? ? ? ? ? ? ? s.Write(block, 0, block.Length); // 寫 5 字節

    ? ? ? ? ? ? ? ? Console.WriteLine(s.Length); // 7

    ? ? ? ? ? ? ? ? Console.WriteLine(s.Position); // 7

    ? ? ? ? ? ? ? ? s.Position = 0; // 回到開頭位置

    ? ? ? ? ? ? ? ? Console.WriteLine(s.ReadByte()); // 101

    ? ? ? ? ? ? ? ? Console.WriteLine(s.ReadByte()); // 102

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?// 從block數組開始的地方開始read:

    ? ? ? ? ? ? ? ? Console.WriteLine(s.Read(block, 0, block.Length)); // 5

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?// 假設最后一次read返回 5, 那就是在文件結尾, 所以read會返回0:

    ? ? ? ? ? ? ? ? Console.WriteLine(s.Read(block, 0, block.Length)); // 0

    ? ? ? ? ? ? }

    ? ? ? ? }

    ? ? }

    }

    運行結果:

    ?

    異步例子:

    using System;

    using System.IO;

    using System.Threading.Tasks;


    namespace Test

    {

    ? ? class Program

    ? ? {

    ? ? ? ? static void Main(string[] args)

    ? ? ? ? {

    ? ? ? ? ? ? Task.Run(AsyncDemo).GetAwaiter().GetResult();

    ? ? ? ? }


    ? ? ? ? async static Task AsyncDemo()

    ? ? ? ? {

    ? ? ? ? ? ? using (Stream s = new FileStream("test.txt", FileMode.Create))

    ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? byte[] block = { 1, 2, 3, 4, 5 };

    ? ? ? ? ? ? ? ? await s.WriteAsync(block, 0, block.Length);?

    ? ? ? ? ? ? ? ? s.Position = 0;

    ? ? ? ? ? ? ? ? Console.WriteLine(await s.ReadAsync(block, 0, block.Length));

    ? ? ? ? ? ? }

    ? ? ? ? }

    ? ? }

    }

    異步版本比較適合慢的stream, 例如網絡的stream.

    讀和寫

    CanRead和CanWrite屬性可以判斷Stream是否可以讀寫.

    Read方法把stream的一塊數據寫入到數組, 返回接受到的字節數, 它總是小于等于count這個參數. 如果它小于count, 就說明要么是已經讀取到stream的結尾了, 要么stream給的數據塊太小了(網絡stream經常這樣).

    一個讀取1000字節stream的例子:

    ? ? ? ? ? ?// 假設s是某個stream

    ? ? ? ? ? ? byte[] data = new byte[1000];

    ? ? ? ? ? ? // bytesRead 的結束位置肯定是1000, 除非stream的長度不足1000

    ? ? ? ? ? ? int bytesRead = 0;

    ? ? ? ? ? ? int chunkSize = 1;

    ? ? ? ? ? ? while (bytesRead < data.Length && chunkSize > 0)

    ? ? ? ? ? ? ? ? bytesRead +=

    ? ? ? ? ? ? ? ? ? ?chunkSize = s.Read(data, bytesRead, data.Length - bytesRead);

    ReadByte方法更簡單一些, 一次就讀一個字節, 如果返回-1表示讀取到stream的結尾了. 返回類型是int.

    Write和WriteByte就是相應的寫入方法了. 如果無法寫入某個字節, 那就會拋出異常.

    上面方法簽名里的offset參數, 表示的是緩沖數組開始讀取或寫入的位置, 而不是指stream里面的位置.

    尋址 Seek

    CanSeek為true的話, Stream就可以被尋址. 可以查詢和修改可尋址的stream(例如文件stream)的長度, 也可以隨時修改讀取和寫入的位置.

    Position屬性就是所需要的, 它是相對于stream開始位置的.

    Seek方法就允許你移動到當前位置或者stream的尾部.

    注意改變FileStream的Position會花去幾微秒. 如果是在大規模循環里面做這個操作的話, 建議使用MemoryMappedFile類.

    對于不可尋址的Stream(例如加密Stream), 想知道它的長度只能是把它讀完. 而且你要是想讀取前一部分的話必須關閉stream, 然后再開始一個全新的stream才可以.

    關閉和Flush

    Stream用完之后必須被處理掉(dispose)來釋放底層資源例如文件和socket處理. 通常使用using來實現.

    • Dispose和Close方法功能上是一樣的.

    • 重復close和flush一個stream不會報錯.

    關閉裝飾器stream的時候會同時關閉裝飾器和它的backing store stream.

    針對一連串的裝飾器裝飾的stream, 關閉最外層的裝飾器就會關閉所有.

    有些stream從backing store讀取/寫入的時候有一個緩存機制, 這就減少了實際到backing store的往返次數以達到提高性能的目的(例如FileStream).

    這就意味著你寫入數據到stream的時候可能不會立即寫入到backing store; 它會有延遲, 直到緩沖被填滿.

    Flush方法會強制內部緩沖的數據被立即的寫入. Flush會在stream關閉的時候自動被調用. 所以你不需要這樣寫: s.Flush(); s.Close();

    超時

    如果CanTimeout屬性為true的話, 那么該stream就可以設定讀或寫的超時.

    網絡stream支持超時, 而文件和內存stream則不支持.

    支持超時的stream, 通過ReadTimeout和WriteTimeout屬性可以設定超時, 單位毫秒. 0表示無超時.

    Read和Write方法通過拋出異常的方式來表示超時已經發生了.

    線程安全

    stream并不是線程安全的, 也就是說兩個線程同時讀或寫一個stream的時候就會報錯.

    Stream通過Synchronized方法來解決這個問題. 該方法接受stream為參數, 返回一個線程安全的包裝結果.

    這個包裝結果在每次讀, 寫, 尋址的時候會獲得一個獨立鎖/排他鎖, 所以同一時刻只有一個線程可以執行操作.

    實際上, 這允許多個線程同時為同一個數據追加數據, 而其他類型的操作(例如同讀)則需要額外的鎖來保證每個線程可以訪問到stream相應的部分.

    Backing Store Stream

    FileStream

    文件流

    構建一個FileStream:?

    FileStream fs1 = File.OpenRead("readme.bin"); // Read-onlyFileStream fs2 = File.OpenWrite(@"c:\temp\writeme.tmp"); // Write-onlyFileStream fs3 = File.Create(@"c:\temp\writeme.tmp"); // Read/write

    ?

    OpenWrite和Create對于已經存在的文件來說, 它的行為是不同的.

    Create會把現有文件的內容清理掉, 寫入的時候從頭開寫.

    OpenWrite則是完整的保存著現有的內容, 而stream的位置定位在0. 如果寫入的內容比原來的內容少, 那么OpenWrite打開并寫完之后的內容是原內容和新寫入內容的混合體.

    直接構建FileStream:

    var fs = new FileStream ("readwrite.tmp", FileMode.Open); // Read/write

    ?

    其構造函數里面還可以傳入其他參數, 具體請看文檔.

    File類的快捷方法:

    下面這些靜態方法會一次性把整個文件讀進內存:

    • File.ReadAllText(返回string)

    • File.ReadAllLines(返回string數組)?

    • File.ReadAllBytes(返回byte數組)

    下面的方法直接寫入整個文件:

    • File.WriteAllText

    • File.WriteAllLines

    • File.WriteAllBytes

    • File.AppendAllText?(很適合附加log文件)?

    還有一個靜態方法叫File.ReadLines: 它有點想ReadAllLines, 但是它返回的是一個懶加載的IEnumerable<string>. 這個實際上效率更高一些, 因為不必一次性把整個文件都加載到內存里. LINQ非常適合處理這個結果. 例如:

    int longLines = File.ReadLines ("filePath").Count (l => l.Length > 80);

    ?

    指定的文件名:

    可以是絕對路徑也可以是相對路徑.

    可已修改靜態屬性Environment.CurrentDirectory的值來改變當前的路徑. (注意: 默認的當前路徑不一定是exe所在的目錄)

    AppDomain.CurrentDomain.BaseDirectory會返回應用的基目錄, 它通常是包含exe的目錄.?

    指定相對于這個目錄的地址最好使用Path.Combine方法:

    string baseFolder = AppDomain.CurrentDomain.BaseDirectory; ? ? ? ? ? ?string logoPath = Path.Combine(baseFolder, "logo.jpg");Console.WriteLine(File.Exists(logoPath));

    ?

    通過網絡對文件讀寫要使用UNC路徑:

    例如: \\JoesPC\PicShare \pic.jpg 或者 \\10.1.1.2\PicShare\pic.jpg.

    FileMode:

    所有的FileStream的構造器都會接收一個文件名和一個FileMode枚舉作為參數. 如果選擇FileMode請看下圖:

    其他特性還是需要看文檔.

    MemoryStream

    MemoryStream在隨機訪問不可尋址的stream時就有用了.

    如果你知道源stream的大小可以接受, 你就可以直接把它復制到MemoryStream里:

    var ms = new MemoryStream();sourceStream.CopyTo(ms);

    ?

    可以通過ToArray方法把MemoryStream轉化成數組.

    GetBuffer方法也是同樣的功能, 但是因為它是直接把底層的存儲數組的引用直接返回了, 所以會更有效率. 不過不幸的是, 這個數組通常比stream的真實長度要長.

    注意: Close和Flush 一個MemoryStream是可選的. 如果關閉了MemoryStream, 你就再也不能對它讀寫了, 但是仍然可以調用ToArray方法來獲取其底層的數據.

    Flush則對MemoryStream毫無用處.

    PipeStream

    PipeStream通過Windows Pipe 協議, 允許一個進程(process)和另一個進程通信.

    分兩種:

    • 匿名進程(快一點), 允許同一個電腦內的父子進程單向通信.

    • 命名進程(更靈活), 允許同一個電腦內或者同一個windows網絡內的不同電腦間的任意兩個進程間進行雙向通信

    pipe很適合一個電腦上的進程間交互(IPC), 它并不依賴于網絡傳輸, 這也意味著沒有網絡開銷, 也不在乎防火墻.

    注意: pipe是基于Stream的, 一個進程等待接受一串字符的同時另一個進程發送它們.

    PipeStream是抽象類.

    具體的實現類有4個:

    匿名pipe:

    • AnonymousePipeServerStream

    • AnonymousePipeClientStream

    命名Pipe:

    • NamedPipeServerStream

    • NamePipeClientStream

    命名Pipe

    命名pipe的雙方通過同名的pipe進行通信. 協議規定了兩個角色: 服務器和客戶端. 按照下述方式進行通信:

    • 服務器實例化一個NamedPipeServerStream然后調用WaitForConnection方法.

    • 客戶端實例化一個NamedPipeClientStream然后調用Connect方法(可以設定超時).

    然后雙方就可以讀寫stream來進行通信了.

    例子:

    using System;

    using System.IO;

    using System.IO.Pipes;

    using System.Threading.Tasks;


    namespace Test

    {

    ? ? class Program

    ? ? {

    ? ? ? ? static void Main(string[] args)

    ? ? ? ? {

    ? ? ? ? ? ? Console.WriteLine(DateTime.Now.ToString());

    ? ? ? ? ? ? using (var s = new NamedPipeServerStream("pipedream"))

    ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? s.WaitForConnection();

    ? ? ? ? ? ? ? ? s.WriteByte(100); // Send the value 100.

    ? ? ? ? ? ? ? ? Console.WriteLine(s.ReadByte());

    ? ? ? ? ? ? }

    ? ? ? ? ? ? Console.WriteLine(DateTime.Now.ToString());

    ? ? ? ? }

    ? ? }

    }

    using System;

    using System.IO.Pipes;


    namespace Test2

    {

    ? ? class Program

    ? ? {

    ? ? ? ? static void Main(string[] args)

    ? ? ? ? {

    ? ? ? ? ? ? Console.WriteLine(DateTime.Now.ToString());

    ? ? ? ? ? ? using (var s = new NamedPipeClientStream("pipedream"))

    ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? s.Connect();

    ? ? ? ? ? ? ? ? Console.WriteLine(s.ReadByte());

    ? ? ? ? ? ? ? ? s.WriteByte(200); // Send the value 200 back.

    ? ? ? ? ? ? }

    ? ? ? ? ? ? Console.WriteLine(DateTime.Now.ToString());

    ? ? ? ? }

    ? ? }

    }

    命名的PipeStream默認情況下是雙向的, 所以任意一方都可以進行讀寫操作, 這也意味著服務器和客戶端必須達成某種協議來協調它們的操作, 避免同時進行發送和接收.

    還需要協定好每次傳輸的長度.

    在處理長度大于一字節的信息的時候, pipe提供了一個信息傳輸的模式, 如果這個啟用了, 一方在調用read的時候可以通過檢查IsMessageComplete屬性來知道消息什么時候結束.

    例子:

    static byte[] ReadMessage(PipeStream s)

    ? ? ? ? {

    ? ? ? ? ? ? MemoryStream ms = new MemoryStream();

    ? ? ? ? ? ? byte[] buffer = new byte[0x1000]; // Read in 4 KB blocks

    ? ? ? ? ? ? do { ms.Write(buffer, 0, s.Read(buffer, 0, buffer.Length)); }

    ? ? ? ? ? ? while (!s.IsMessageComplete); return ms.ToArray();

    ? ? ? ? }

    注意: 針對PipeStream不可以通過Read返回值是0的方式來它是否已經完成讀取消息了. 這是因為它和其他的Stream不同, pipe stream和network stream沒有確定的終點. 在兩個信息傳送動作之間, 它們就干等著.

    這樣啟用信息傳輸模式, 服務器端 :

    using (var s = new NamedPipeServerStream("pipedream", PipeDirection.InOut, 1, PipeTransmissionMode.Message))

    ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? s.WaitForConnection();

    ? ? ? ? ? ? ? ? byte[] msg = Encoding.UTF8.GetBytes("Hello");

    ? ? ? ? ? ? ? ? s.Write(msg, 0, msg.Length);

    ? ? ? ? ? ? ? ? Console.WriteLine(Encoding.UTF8.GetString(ReadMessage(s)));

    ? ? ? ? ? ? }

    客戶端:?

    using (var s = new NamedPipeClientStream("pipedream"))

    ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? s.Connect();

    ? ? ? ? ? ? ? ? s.ReadMode = PipeTransmissionMode.Message;

    ? ? ? ? ? ? ? ? Console.WriteLine(Encoding.UTF8.GetString(ReadMessage(s)));

    ? ? ? ? ? ? ? ? byte[] msg = Encoding.UTF8.GetBytes("Hello right back!");

    ? ? ? ? ? ? ? ? s.Write(msg, 0, msg.Length);

    ? ? ? ? ? ? }

    匿名pipe:

    匿名pipe提供父子進程間的單向通信. 流程如下:

    • 服務器實例化一個AnonymousPipeServerStream, 并指定PipeDirection是In還是Out

    • 服務器調用GetClientHandleAsString方法來獲取一個pipe的標識, 然后會把它傳遞給客戶端(通常是啟動子進程的參數 argument)

    • 子進程實例化一個AnonymousePipeClientStream, 指定相反的PipeDirection

    • 服務器通過調用DisposeLocalCopyOfClientHandle釋放步驟2的本地處理,?

    • 父子進程間通過讀寫stream進行通信

    因為匿名pipe是單向的, 所以服務器必須創建兩份pipe來進行雙向通信

    例子:

    server:

    using System;

    using System.Diagnostics;

    using System.IO;

    using System.IO.Pipes;

    using System.Text;

    using System.Threading.Tasks;


    namespace Test

    {

    ? ? class Program

    ? ? {

    ? ? ? ? static void Main(string[] args)

    ? ? ? ? {

    ? ? ? ? ? ? string clientExe = @"D:\Projects\Test2\bin\Debug\netcoreapp2.0\win10-x64\publish\Test2.exe";

    ? ? ? ? ? ? HandleInheritability inherit = HandleInheritability.Inheritable;

    ? ? ? ? ? ? using (var tx = new AnonymousPipeServerStream(PipeDirection.Out, inherit))

    ? ? ? ? ? ? using (var rx = new AnonymousPipeServerStream(PipeDirection.In, inherit))

    ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? string txID = tx.GetClientHandleAsString();

    ? ? ? ? ? ? ? ? string rxID = rx.GetClientHandleAsString();

    ? ? ? ? ? ? ? ? var startInfo = new ProcessStartInfo(clientExe, txID + " " + rxID);

    ? ? ? ? ? ? ? ? startInfo.UseShellExecute = false; // Required for child process

    ? ? ? ? ? ? ? ? Process p = Process.Start(startInfo);

    ? ? ? ? ? ? ? ? tx.DisposeLocalCopyOfClientHandle(); // Release unmanaged

    ? ? ? ? ? ? ? ? rx.DisposeLocalCopyOfClientHandle(); // handle resources.

    ? ? ? ? ? ? ? ? tx.WriteByte(100);

    ? ? ? ? ? ? ? ? Console.WriteLine("Server received: " + rx.ReadByte());

    ? ? ? ? ? ? ? ? p.WaitForExit();

    ? ? ? ? ? ? }

    ? ? ? ? }

    ? ? }

    }

    client:

    using System;

    using System.IO.Pipes;


    namespace Test2

    {

    ? ? class Program

    ? ? {

    ? ? ? ? static void Main(string[] args)

    ? ? ? ? {

    ? ? ? ? ? ? string rxID = args[0]; // Note we're reversing the

    ? ? ? ? ? ? string txID = args[1]; // receive and transmit roles.

    ? ? ? ? ? ? using (var rx = new AnonymousPipeClientStream(PipeDirection.In, rxID))

    ? ? ? ? ? ? using (var tx = new AnonymousPipeClientStream(PipeDirection.Out, txID))

    ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? Console.WriteLine("Client received: " + rx.ReadByte());

    ? ? ? ? ? ? ? ? tx.WriteByte(200);

    ? ? ? ? ? ? }

    ? ? ? ? }

    ? ? }

    }

    最好發布一下client成為獨立運行的exe:

    dotnet publish --self-contained --runtime win10-x64

    ?

    運行結果:

    ?

    匿名pipe不支持消息模式, 所以你必須自己來為傳輸的長度制定協議. 有一種做法是: 在每次傳輸的前4個字節里存放一個整數表示消息的長度, 可以使用BitConverter類來對整型和長度為4的字節數組進行轉換.

    BufferedStream

    BufferedStream對另一個stream進行裝飾或者說包裝, 讓它擁有緩沖的能力.它也是眾多裝飾stream類型中的一個.

    緩沖肯定會通過減少往返backing store的次數來提升性能.

    下面這個例子是把一個FileStream裝飾成20k的緩沖stream:

    ? ? ? ? ? ?// Write 100K to a file:

    ? ? ? ? ? ? File.WriteAllBytes("myFile.bin", new byte[100000]);

    ? ? ? ? ? ? using (FileStream fs = File.OpenRead("myFile.bin"))

    ? ? ? ? ? ? using (BufferedStream bs = new BufferedStream(fs, 20000)) //20K buffer

    ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? bs.ReadByte();

    ? ? ? ? ? ? ? ? Console.WriteLine(fs.Position); // 20000

    ? ? ? ? ? ? }

    ? ? ? ? }

    通過預讀緩沖, 底層的stream會在讀取1字節后, 直接預讀了20000字節, 這樣我們在另外調用ReadByte 19999次之后, 才會再次訪問到FileStream.

    這個例子是把BufferedStream和FileStream耦合到一起, 實際上這個例子里面的緩沖作用有限, 因為FileStream有一個內置的緩沖. 這個例子也只能擴大一下緩沖而已.

    關閉BufferedStream就會關閉底層的backing store stream..?

    先寫到這里, 略微有點跑題了, 但是.NET Core的Stream這部分沒寫完, 另開一篇文章再寫吧.


    原文地址?https://www.cnblogs.com/cgzl/p/8697949.html


    .NET社區新聞,深度好文,歡迎訪問公眾號文章匯總 http://www.csharpkit.com

    總結

    以上是生活随笔為你收集整理的用.NET Core实现装饰模式和.NET Core的Stream简介的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 色婷婷国产精品视频 | 欧洲一级黄| 在线观看自拍 | 吖v在线| 女人一区二区 | 奇米色综合 | 亚洲美女毛片 | 国产精品国产三级国产aⅴ下载 | 台湾佬美性中文娱乐网 | 欧美熟妇精品一区二区 | 爱爱视频在线看 | 首尔之春在线观看 | 麻豆免费视频网站 | 亚洲免费视频一区二区三区 | 精品妇女一区二区三区 | 日韩va在线 | 国产中文在线播放 | av最新版天堂资源在线 | 国产一级大片在线观看 | 热99视频| 欧美猛操| 日韩在线激情视频 | 亚洲九九 | 日韩欧美xxxx | 午夜精品久久久久久久99黑人 | 国产日本欧美一区二区 | 97久久国产 | 51成人做爰www免费看网站 | 亚洲射吧| 开心激情网五月天 | 成人精品在线观看 | xxxx精品| 原创av | 一级黄色在线观看 | 久久久蜜桃一区二区人 | 正在播放亚洲 | 国产精品美女久久 | 亚洲一区二区色图 | 五月天色小说 | 日韩欧美亚洲国产精品字幕久久久 | 国产无遮挡又黄又爽 | 亚洲字幕av一区二区三区四区 | 18无码粉嫩小泬无套在线观看 | 鬼灭之刃柱训练篇在线观看 | 91porn破解版 | 日本特级黄色片 | 日韩一级欧美一级 | 成人麻豆视频 | 亚洲精品成人网 | 精品一区二区三区免费毛片 | 亚洲无av在线中文字幕 | 国内精品国产三级国产aⅴ久 | 伊人网站在线观看 | 色情毛片 | 免费看片色| 天天爱天天干天天操 | 二男一女一级一片 | 99在线免费观看 | 寂寞人妻瑜伽被教练日 | 久久久午夜电影 | 欧美成人激情在线 | 91久久国产 | www男人天堂| 4438全国成人免费 | 五月天青青草 | 亚洲一级影院 | 国产3p在线播放 | 69精品人妻一区二区三区 | 污网址在线观看 | 天天综合日韩 | 男女无遮挡网站 | 精品不卡一区二区三区 | 久久人人爱 | 国产成人精品一区二区色戒 | 日日干夜夜爱 | 国产情侣在线视频 | 久久精品欧美一区二区三区不卡 | 久久99精品久久久久久噜噜 | 国产suv精品一区二区33 | 国产又大又粗又爽的毛片 | 黄色av免费在线播放 | 日本一区二区视频在线播放 | 乱短篇艳辣500篇h文最新章节 | 国精产品99永久一区一区 | 亚洲成人午夜在线 | 欧美日韩精品一区二区在线播放 | 极品久久久久久 | 97超碰成人| www.色日本| 久久视频精品在线 | 男人操女人的视频 | 性色福利| 亚洲一区免费视频 | 午夜肉体高潮免费毛片 | 国产无限制自拍 | 久久加久久 | 精品婷婷| 欧美福利专区 | 国产素人在线 |