Chapter 4 - Item 35 : Never Overload Extension Methods

Effective C# (Covers C# 6.0), (includes Content Update Program): 50 Specific Ways to Improve Your C#, 3rd Edition By Bill Wagner 讀後心得

本節將介紹擴充方法不當的使用方式,意即不要利用命名空間多載擴充方法;此舉會造成使用端誤用與意圖不明。

範例:

public sealed class Person
{
    public string FirstName { get; set; }

    public string LastName { get; set; }
}

namespace ConsoleExtension
{
    public static class ConoleReport
    {
        public static string format( this Person target ) =>
            $"{target.FirstName,20}, {target.LastName,15}";
    }
}

namespace XmlExtension
{
    public static class XmlReport
    {
        public static string format( this Person target ) =>
            new XElement( nameof( Person ),
                new XElement( nameof( target.LastName ), target.LastName ),
                new XElement( nameof( target.FirstName ), target.LastName )
                ).ToString( );
    }
}

用戶端程式:

var somePresidents = new List<Person>
{
    new Person
    {
        FirstName = "George",
        LastName = "Washington"
    },

    new Person
    {
        FirstName = "Thomas",
        LastName = "Jefferson"
    },

    new Person
    {
        FirstName = "Abe",
        LastName = "Lincoln"
    }
};

foreach ( var person in somePresidents )
    Debug.WriteLine( p.Format( ) );

這樣設計有幾個問題:
1. ConsoleReport 與 XmlReport 靜態類別皆定義了相同的方法簽章 format,造成用戶端無法透過方法名稱得知意圖。

2. 同時參考兩者 namespace 會造成 compile error。

3. 變更參考 namespace 以達到呼叫不同 format 的方式容易出錯(參考不當)。

4. format 本身不應寫成擴充方法,format 並非由 Person 擴充出去,而是外部使用 Person 物件的方式。

修改後程式碼:

namespace PersonExtensions
{
    public static class PersonReports
    {
        public static string formatAsText( Person target ) =>
            $"{target.FirstName,20}, {target.LastName,15}";

        public static string formatAsXml( Person target ) =>
            new XElement( nameof( Person ),
                new XElement( nameof( target.LastName ), target.LastName ),
                new XElement( nameof( target.FirstName ), target.LastName )
                ).ToString( );
    }
}

1. 使用明確的方法命名。

2. 並非寫成擴充方法,而是用靜態方法傳入 Person 物件參數。

3. 統一 namespace。

結論:
1. 不要利用命名空間多載擴充方法。

2. 撰寫擴充方法前,先考慮該方法是否應該由該類別"擴充"出去。