C#學習筆記7

来源:http://www.cnblogs.com/zwt-blog/archive/2017/01/19/6305881.html
-Advertisement-
Play Games

1.重寫GetHashCode方法註意點: (1)重寫GetHashCode方法,也應重寫Equals方法,否者編譯器會警告。 (2)相等的對象必須有相等的散列碼(若a.Equals(b),則a.GetHashCode()==b.GetHashCode())。 (3)GetHashCode()不應引 ...


1.重寫GetHashCode方法註意點:

(1)重寫GetHashCode方法,也應重寫Equals方法,否者編譯器會警告。

(2)相等的對象必須有相等的散列碼(若a.Equals(b),則a.GetHashCode()==b.GetHashCode())。

(3)GetHashCode()不應引發任何異常,GetHashCode()必須總是成功的返回一個值。

(4)散列碼應該儘可能的保持唯一。

(5)GetHashCode()的性能應該優化,GetHashCode()通常在Equals()實現中用於“短路”一次完整的相等性比較(假如散列碼不同,當然就沒有必要進行完整的相等性比較了),所以當類型作為字典集合中的鍵類型使用時,會頻繁地調用這個方法。

(6)針對一個特定的對象,在這個對象的生存期內,GetHashCode()始終應該返回相同的值,即使對象的數據發生了改變。在許多時候,應該緩存方法的返回值,從而確保這一點。

  Other:我們通常採取的做法是為來自相應類型的散列碼應用XOR(異或)運算符,並確保XOR的操作數不相近或相等,否則結果會全是零。在操作數相近或相等的情況下,考慮使用移位和加法操作。其他的備選運算符--AND和OR--具有類似的限制,這些限制會發生的更加頻繁,多次使用AND會逐漸變成全為0;而多次應用OR會逐漸變成全為1。為了進行更細緻的控制,應該使用移位運算符來分解一個比int大的類型。例如,假定有一個名為value的long類型,它的GetHashCode()方法可以像下麵這樣實現:int GetHashCode(){return (int)value ^ (int)(value >> 32)}。

2.在object中,Equals()這個virtual方法的實現是用ReferenceEquals()來評判相等性。因為這個實現往往都是不充分,所以一般都有必要重寫Equals()方法。

3.重寫Equals()方法註意點,:

(1)檢查是否為null;

(2)如果是引用類型,就檢查引用是否相等;

(3)可能要檢查散列碼是否相等,如果散列碼不相等,就沒有必要繼續執行一次全面的、逐欄位的比較。(相等的兩個對象不可能散列碼不同)

(4)比較每一個標識欄位,判斷是否相等。

4.相等性實現的指導原則:

(1)Equals()、==運算符和!=運算符應該一起實現;

(2)一個類型在Equals()、==和!=實現中應該使用相同的演算法;

(3)實現Equals()、==和!=時,也應實現一個類型的GetHashCode()方法;

(4)GetHashCode()、Equals()、==和!=永遠不能引發異常;

(5)實現IComparable時,與相等性有關的方法也應實現;

可以查看Coordinate類的定義便於直觀瞭解。

5.其他二元運算符(如“+、-、&”)的定義:就像“==”定義一樣,其中至少有一個參數的類型是本類型(當前重載運算符的類型)。在重定義了這些二元運算符後,就可以像操作基本的數值類型一樣進行運算。可查看Coordinate類。

6.其他的一元運算符(如“+正、-負、!、true、false”)的重載與重載二元運算符類似,只是重載“true、false”要成對出現,重載的參數變成了一個。其中的“true、false”運算符主要應用與if、do...while、for這些控製表達式使用。

7.轉型運算符:轉型運算符分為顯式(explicit)與隱式(implicit),隱式轉型總是成功,顯式轉型提醒用戶這是不希望的行為,顯式存在2個問題“①轉換可能會有異常,②轉換可能會存在部分數據丟失”。可查看Angle結構的代碼示例。

8.命名空間:命名空間可以嵌套,就是類一樣可以嵌套,命名空間的嵌套有2種,分別為聲明層次的嵌套;聲明時“.”符號隔開。如 System.IO。

9.生成類文件的註釋的xml文檔:可以在VS的命令工具中使用“csc /doc:文檔名.xml 類文件”。其實也可以在VS-IDE的項目屬性=>生成=>設置xml文檔輸出,即可生成項目文檔說明,當然可以使用一些免費工具進行文檔生成(如GhostDoc、NDoc)。在把程式集提供給他人使用時(程式集是不含文檔說明,編譯器會把源代碼中註釋忽略),若要使VS IntelliSense提示程式集中的成員說明信息,需讓XML文件的文件名與您要支持的程式集相同,確保XML文件與程式集位於同一個目錄中,從而在Visual Studio項目中引用程式集時,也可以找到.xml文件。

10.終結器:終結器是用來清理一個類的占用的昂貴的資源(如資料庫連接、文件句柄),其不能顯式調用,是由垃圾回收器負責調用,因此我們不能在編譯時確定終結器執行的時機,唯一確定的是終結器會在上一次使用對象之後,併在應用程式關閉之前的某個時間運行。其聲明的方式是“~類名(){}”,不允許傳遞參數與添加如public修飾符,因為其本身是不能顯式調用。基類中的終結器會作為對象終結調用的一部分而自動調用。可查看TemporaryFileStream類的處理代碼。

11.使用using語句進行確定性的終結:終結器本身的問題在於,它們不支持一個確定性終結(也就是預知一個終結器的運行時間的能力),相反,終結器是作為對資源清理的一個備用機制來使用。假如開發者忘記顯式調用必要的清理代碼,就可以依賴終結器來清理資源。要進行確定的終結需要類本身實現IDisposable介面,該介面內包含Dispose()方法,需要自己實現具體的細節來清理資源。使用using語句終結和使用try-finally處理是一個效果,因為此處的using語句在最終生成的CIL代碼上就是try-finally,using語句只是提供了try-fianlly塊的一個語法快捷方式。在using中可以實例化多個類型一致的變數,來一起處理釋放。可查看TemporaryFileStream類的處理代碼。

12.資源利用與終結的指導原則:

(1)只有在對象使用了稀缺或昂貴資源的前提下,才為對象實現finalize,終結會推遲垃圾回收。

(2)有終結器的對象應該實現IDisposable介面來支持確定性的終結。

(3)終結方法通常調用與IDisposable調用相同的代碼。

(4)終結器應避免造成任何未處理的異常。

(5)像Dispose()和Close()這樣的確定性終結方法應該調用GC.SuppressFinalize(),使垃圾回收更快的發生。

(6)資源清理方法應該足夠簡單,而且只應著重於清理由終結實例引用的資源。

(7)若基類實現了Dispose(),則派生實現應調用基類的實現。

13.延遲初始化Lazy<T>:在.net4.0中提供了Lazy<T>可對對象進行延遲初始化(即需要該對象時才被創建),可查看DataCache類的實現。

 

public class Coordinate
{
    /// <summary>
    /// 經度
    /// </summary>
    public Angle Longitude { get; set; }
    /// <summary>
    /// 維度
    /// </summary>
    public Angle Latitude { get; set; }

    public override int GetHashCode()
    {
        int hashCode = Longitude.GetHashCode();
        if (hashCode != Latitude.GetHashCode())
        {
            hashCode ^= Latitude.GetHashCode();
        }
        return hashCode;
    }

    public override bool Equals(object obj)
    {
        if (obj == null)
        {
            return false;
        }
        return Equals((Coordinate)obj);
    }

    public bool Equals(Coordinate obj)
    {
        if (obj == null)
        {
            return false;
        }
        if (GetHashCode() != obj.GetHashCode())
        {
            return false;
        }
        return Longitude.Equals(obj.Longitude) && Latitude.Equals(obj.Latitude);
    }

    public static bool operator ==(Coordinate one, Coordinate two)
    {
        if (ReferenceEquals(one, null))//此處不用==判斷null,是因為我們重定義了本類的“==”操作符,否則會進入遞歸造成死迴圈。
        {
            return ReferenceEquals(two, null);
        }
        return one.Equals(two);
    }

    public static bool operator !=(Coordinate one, Coordinate two)
    {
        return !(one == two);
    }

    public static Coordinate operator +(Coordinate one, Coordinate two)
    {
        return new Coordinate()
        {
            Longitude = one.Longitude + two.Longitude,
            Latitude = one.Latitude + two.Latitude
        };
    }

    public static bool operator !(Coordinate one)
    {
        return false;
    }

    public static bool operator true(Coordinate one)
    {
        return one.Latitude.Hours > 0 && one.Latitude.Minutes > 0 && one.Latitude.Seconds > 0;
    }

    public static bool operator false(Coordinate one)
    {
        if (one)
        {
            return false;
        }
        return true;
    }
}

public struct Angle
{
    public Angle(int hours, int minutes, int seconds)
    {
        Hours = hours;
        Minutes = minutes;
        Seconds = seconds;
    }
    public int Hours { get; set; }
    public int Minutes { get; set; }
    public int Seconds { get; set; }

    public Angle Move(int hours, int minutes, int seconds)
    {
        return new Angle(Hours + hours, Minutes + minutes, Seconds + seconds);
    }

    public override int GetHashCode()
    {
        return base.GetHashCode();
    }

    public override bool Equals(object obj)
    {
        return Equals((Angle)obj);
    }

    public bool Equals(Angle obj)
    {
        return Hours == obj.Hours && Minutes == obj.Minutes && Seconds == obj.Seconds;
    }

    public static Angle operator +(Angle one, Angle two)
    {
        return one.Move(two.Hours, two.Minutes, two.Seconds);
    }

    public static implicit operator string(Angle one)
    {
        return string.Format("{0},{1},{2}", one.Hours, one.Minutes, one.Seconds);
    }

    public static explicit operator Angle(string text)
    {
        try
        {
            var result = text.Split(',').Cast<int>();
            return new Angle(result.ElementAt(0), result.ElementAt(1), result.ElementAt(2));
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }
}

public class TemporaryFileStream : IDisposable
{
    public TemporaryFileStream(string fileName)
    {
        //todo
    }

    ~TemporaryFileStream()
    {
        Dispose();
    }

    private readonly FileStream _stream;
    public FileStream Stream
    {
        get { return _stream; }
    }

    private readonly FileInfo _file;
    public FileInfo File
    {
        get { return _file; }
    }

    public void Dispose()
    {
        Stream?.Close();
        File?.Delete();
        /*該語句的作用是從終結列隊中移除TemporaryFileStream類實例,一個對象在終結列隊中就是不會進行垃圾回收,必須終結後才能垃圾回收,執行此語句就不會推遲該對象的
        垃圾回收。*/
        GC.SuppressFinalize(this);
    }
}

public class DataCache
{
    public DataCache()
    {
        _fileStream = new Lazy<TemporaryFileStream>(() => new TemporaryFileStream(FileStreamName));
    }
    public string FileStreamName { get; set; }

    private Lazy<TemporaryFileStream> _fileStream;
    public TemporaryFileStream FileStream
    {
        //只有在返回“value”時,才會執行“() => new TemporaryFileStream(FileStreamName)”代碼,
        get { return _fileStream.Value; }
    }

    /* .net4.0以前模擬的延遲初始化對象
    private TemporaryFileStream _fileStream;
    public TemporaryFileStream FileStream
    {
        get
        {
            if (_fileStream == null)
            {
                _fileStream = new TemporaryFileStream(FileStreamName);
            }
            return _fileStream;
        }
    }*/
}

 

------------------------以上內容根據《C#本質論 第三版》進行整理


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1.桌面右擊新建txt文件複製下麵兩行代碼,修改文件尾碼名為bat保存文件 netsh wlan set hostednetwork mode=allow ssid=zhangxh key=xiaoheng123netsh wlan start hostednetwork 2.右擊bat文件以管理員 ...
  • 1 塊設備的概述 linux支持的兩種重要的設備類型分別是字元設備和塊設備,塊設備可以隨機地以固定大小的塊傳送數據。與字元設備相比,塊設備有以下幾個特殊之處: (1)塊設備可以從數據的任何位置進行訪問 (2)塊數據總是以固定長度進行傳輸,即便請求的這是一個位元組 (3)對塊設備的訪問有大量的緩存。當進 ...
  • 去埠號功能主要用於Apache與IIS等WEB伺服器共存時,去除功能變數名稱後面所帶的埠 本文案例採用我開發的純綠色PHP集成環境PHPWAMP裡面的“去埠”功能模塊。 案例演示: 點擊常用工具,打開“去掉功能變數名稱非80埠”功能即可 彈出的界面菜單如下圖 如下填寫,功能變數名稱填寫格式abc.com,具體如下圖 ...
  • 最近有學生向我咨詢如何同時建立多個不同PHP版本站點,並自定義任意版本,軟體是否可以多開,PHPWAMP如何設置才能與其他的環境同時使用等問題,本文將一一解決。 簡單介紹一下PHPWAMP 你們應該會經常聽到WAMP這詞吧,那麼WAMP是什麼意思? Windows下的Apache+Mysql+PHP ...
  • phpwamp在伺服器搭建網站,php網站在伺服器上的搭建方式,雲伺服器上如何使用PHP綠色集成環境 ...
  • 1.泛型的約束: (1)介面約束; (2)基類約束,基類約束必須放在第一(假如有多個約束); (3)struct/class約束; (4)多個參數類型的約束,每個類型參數都要用where關鍵字; (5)構造器約束,只能是無參構造器,如new(); (6)約束可以由派生類繼承,但必須在派生類中顯式地指 ...
  • 多線程內容大致分兩部分,其一是非同步操作,可通過專用,線程池,Task,Parallel,PLINQ等,而這裡又涉及工作線程與IO線程;其二是線程同步問題,鄙人現在學習與探究的是線程同步問題。 通過學習《CLR via C#》裡面的內容,對線程同步形成了脈絡較清晰的體繫結構,在多線程中實現線程同步的是 ...
  • 1、設置圖片透明 this.pibox.BackColor = System.Drawing.Color.Transparent; //將背景設置為透明 this.pibox.Parent = lab_show; //將父容器設置為上一層的文件名 2、Timer不起作用 1、先托控制項Timer, 並 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...