現在 Visual Studio 2015 後支援 C# 6.0
string 出現了 $ 符號的應用。
原來字串組合是這麼寫的:
public string ID { set; get; }
public string Name { set; get; }
public string FullName = string.Format("{0}-{1}", ID, Name);
現在可以這樣寫:
public string ID { set; get; }
public string Name { set; get; }
public string FullName = $"{ID}-{Name}";
兩種寫法是一樣的,但是卻大大的增加可讀性。
2017年4月1日 星期六
2017年3月1日 星期三
sealed class 禁止繼承
實做上
通常建立一些管理物件
為了統一控管
不想被多個物件操作
我們可以利用 sealed class 的關鍵字
禁止其他類別繼承 sealed class
藉此操作物件內的資料
以下是 sealed class 的用法
只要繼承 S3Mgr 就會編譯錯誤
通常建立一些管理物件
為了統一控管
不想被多個物件操作
我們可以利用 sealed class 的關鍵字
禁止其他類別繼承 sealed class
藉此操作物件內的資料
以下是 sealed class 的用法
sealed public class S3Mgr
{
....
}
只要繼承 S3Mgr 就會編譯錯誤
partial class 將 class 分成多個 cs 檔
假設某些專案規模很大
總有些 cs 檔案
常常有人修改
程式碼也很多
每每簽入都要處理衝突
或許重構可以根本解決這樣的問題
但是當時間有限沒有足夠的時間做重構
partial class 或許可以解燃眉之急
利用 partial class 可以將 class 分成多個 cs 檔案
編譯器會將 A.cs 與 B.cs 視作是同一個檔案同一個 class
也就是說 A.cs 可以直接取到 B 類別
B.cs 可以直接取到 A 類別
就像是在同一個 class 一樣
這樣的手法
可以幫你分類功能
依據你需要修改的內容
移到獨立的 cs 檔案內
避免多人修改同一個 cs 檔
也能方便管理類別
避免類別內過多的程式碼
有助於程式碼的閱讀
總有些 cs 檔案
常常有人修改
程式碼也很多
每每簽入都要處理衝突
或許重構可以根本解決這樣的問題
但是當時間有限沒有足夠的時間做重構
partial class 或許可以解燃眉之急
利用 partial class 可以將 class 分成多個 cs 檔案
// A.cs 檔
partial class Program
{
public A _a = new A();
....
}
// B.cs 檔
partial class Program
{
public B _a = new B();
....
}
編譯器會將 A.cs 與 B.cs 視作是同一個檔案同一個 class
也就是說 A.cs 可以直接取到 B 類別
B.cs 可以直接取到 A 類別
就像是在同一個 class 一樣
這樣的手法
可以幫你分類功能
依據你需要修改的內容
移到獨立的 cs 檔案內
避免多人修改同一個 cs 檔
也能方便管理類別
避免類別內過多的程式碼
有助於程式碼的閱讀
C# Composite Pattern 組合模式
組合模式最關鍵的地方是簡單對像和復合對像實現相同的接口
/// <summary>
/// 圖形抽像類
/// </summary>
public abstract class Graphics
{
public string Name { get; set; }
public Graphics(string name)
{
this.Name = name;
}
public abstract void Draw();
public abstract void Add(Graphics g);
public abstract void Remove(Graphics g);
}
簡單圖形
/// <summary>
/// 簡單圖形類——線
/// </summary>
public class Line : Graphics
{
public Line(string name)
: base(name)
{ }
// 重寫父類抽像方法
public override void Draw()
{
Console.WriteLine("畫線:" + Name);
}
public override void Add(Graphics g)
{
throw new Exception("不能向簡單圖形Line添加其他圖形");
}
public override void Remove(Graphics g)
{
throw new Exception("不能向簡單圖形Line移除其他圖形");
}
}
/// <summary>
/// 簡單圖形類——圓
/// </summary>
public class Circle : Graphics
{
public Circle(string name)
: base(name)
{ }
// 重寫父類抽像方法
public override void Draw()
{
Console.WriteLine("畫圓:" + Name);
}
public override void Add(Graphics g)
{
throw new Exception("不能向簡單圖形Circle添加其他圖形");
}
public override void Remove(Graphics g)
{
throw new Exception("不能向簡單圖形Circle移除其他圖形");
}
}
複雜圖形
/// <summary>
/// 複雜圖形,由一些簡單圖形組成,假設該複雜圖形由兩條線組成
/// </summary>
public class ComplexGraphics : Graphics
{
private List<Graphics> complexGraphicsList = new List<Graphics>();
public ComplexGraphics(string name)
: base(name)
{ }
/// <summary>
/// 複雜圖形的畫法
/// </summary>
public override void Draw()
{
foreach (Graphics g in complexGraphicsList)
{
g.Draw();
}
}
public override void Add(Graphics g)
{
complexGraphicsList.Add(g);
}
public override void Remove(Graphics g)
{
complexGraphicsList.Remove(g);
}
}
實際執行
class MyClass
{
static void Main(string[] args)
{
ComplexGraphics complexGraphics = new ComplexGraphics("複雜圖形 - 兩條線段組成的複雜圖形");
complexGraphics.Add(new Line("線段A"));
complexGraphics.Add(new Line("線段C"));
// 顯示複雜圖形的畫法
Console.WriteLine("複雜圖形的繪製:");
Console.WriteLine("---------------------");
complexGraphics.Draw();
Console.WriteLine("複雜圖形繪製完成");
Console.WriteLine("---------------------");
}
}
優點:
組合模式介面都一致,可以存在容器統一處理
缺點:複雜度會增加
2017年2月1日 星期三
C# Template Pattern 樣板模式
遇到流程一樣,但是處理邏輯不一樣的狀況,可利用 Template Pattern 樣板模式
建立一個 UnitFlowBase 抽像類別提供框架,裡面有三個方法
Node1 (每個測試類別只都執行一次)
Node2 (每次執行測試方法時都執行一次)
....
UnitTest (執行測試方法,裡面通常會執行多個 UnitFlowBase 提供的方法
所以才會說 UnitFlowBase 提供框架,例如:此範例 UnitTest 執行了 Node2() 與 Node3())
public abstract class UnitFlowBase
{
protected UnitFlowBase()
{
Node1();
}
protected virtual void Node1()
{
}
protected virtual void Node2()
{
}
protected abstract bool Node3();
public void UnitTest()
{
Node2();
Console.WriteLine(Node3() ? "Assert Successful." : "Assert Fail.");
}
}
建立 UnitCounter1 與 UnitCounter2
Execute方法 顯示目前 ClassCount 跟 MethodCount 執行次數
public class UnitCounter1 : UnitFlowBase
{
private int _classCounter = 0;
private int _methodCounter = 0;
protected override void Node1()
{
_classCounter++;
}
protected override void Node2()
{
_methodCounter++;
}
protected override bool Node3()
{
Console.WriteLine($"ClassCounter1 : {_classCounter}");
Console.WriteLine($"MethodCounter1: { _methodCounter}");
return true;
}
}
public class UnitCounter2 : UnitFlowBase
{
private int _classCounter = 0;
private int _methodCounter = 0;
protected override void Node1()
{
_classCounter += 2;
}
protected override void Node2()
{
_methodCounter += 2;
}
protected override bool Node3()
{
Console.WriteLine($"ClassCounter2 : {_classCounter}");
Console.WriteLine($"MethodCounter2: { _methodCounter}");
return true;
}
}
建立一個 UnitCounter1 與 UnitCounter2 類別,各執行二次 UnitTest 方法
class Program
{
static void Main(string[] args)
{
UnitCounter1 unit1_ = new UnitCounter1();
UnitCounter2 unit2_ = new UnitCounter2();
unit1_.UnitTest();
unit1_.UnitTest();
unit2_.UnitTest();
unit2_.UnitTest();
}
}
執行結果:
ClassCount : 1
MethodCount : 1
Assert Successfull.
ClassCount : 1
MethodCount : 2
Assert Successfull.
ClassCount : 2
MethodCount : 2
Assert Successfull.
ClassCount : 2
MethodCount : 4
Assert Successfull.
2017年1月2日 星期一
設計模式 Simple Factory 簡單工廠模式
情境:
要設計一個連接資料庫的物件,提供 MSSQL 與 MYSQL 兩種連線方式
讓使用者使用
1.首先定一個介面
要設計一個連接資料庫的物件,提供 MSSQL 與 MYSQL 兩種連線方式
讓使用者使用
1.首先定一個介面
public interface IDBConnection
{
void GetIDBConnection();
}
2.實作 MYSQL 與 MSSQL 資料庫連線方式
public class MSSQL : IDBConnection
{
public void GetDBConnection()
{
Console.WriteLine("MYSQL連線 ");
}
}
public class MYSQL:IDBConnection
{
public void GetDBConnection()
{
Console.WriteLine("MYSQL 連線");
}
}
3.實做工廠類別
public class ConnectionFactory
{
public static IDDConnection GetConnection(DBType type)
{
IDDConnection db_ = null;
switch (type)
{
case DBType.MySQL:
db_ = new MYSQL();
break;
case DBType.MSSQL:
db_ = new MSSQL();
break;
default:
Console.WriteLine("default type");
break;
}
return db_ ;
}
}
4.外部使用簡單工廠模式
class Program
{
static void Main(string[] args)
{
IDBConnection Connection_ = ConnectionFactory.GetConnection(DBType.MySQL);
Connection.GetDBConnection();
Console.ReadKey();
}
}
Blogger 顯示好看的程式碼內容(Code Block)
網路上查了一下 Code Block 發現 Google Code Prettify 看起來蠻順眼的, 就在這邊記錄一下設定的過程,留下筆記以便於日後查詢。
點選「版面配置」
在中間的位置點擊「新增小工具」
填入標題 Google Code Prettify
填入內容
選一個順眼的程式碼格式
Color themes for Google Code Prettify
使用方式如下
linenums 是顯示行號
language-cs 是指定 cs 的格式
範例程式碼
點選「版面配置」
在中間的位置點擊「新增小工具」
點擊「HTML/JavaScript」
填入標題 Google Code Prettify
填入內容
選一個順眼的程式碼格式
Color themes for Google Code Prettify
使用方式如下
linenums 是顯示行號
language-cs 是指定 cs 的格式
範例程式碼
C# 二進制字串轉數值
範例:將字串 "1000000000000000000" 轉成 int 數值
using System;
using System.Text.RegularExpressions;
namespace BinaryStringToInteger
{
class Program
{
static void Main(string[] args)
{
BinaryStringToInteger("1000000000000000000");
Console.ReadKey();
}
static readonly Regex Binary = new Regex("^[01]{1,32}$", RegexOptions.Compiled);
static void BinaryStringToInteger(string s)
{
if (Binary.IsMatch(s))
{
Console.WriteLine(Convert.ToInt32(s, 2));
}
else
{
Console.WriteLine("invalid: " + s);
}
}
}
}
設計模式 C# 的 Singleton 的泛型
讓人繼承就可已變成 Singleton 獨體
///
/// 給人繼承成為獨體
///
/// 要繼承的類別
public class Singleton where T : class, new()
{
protected Singleton()
{
Debug.Assert(null == _instance);
}
private static readonly T _instance = new T();
public static T Instance
{
get
{
return _instance;
}
}
}
Function Composition
由多個小 function 組合成大 function
EmailFor() 能根據 User 的 姓 與 名 自動產生 email
string EmailTo(User u) => Domain(FullName(u));
EmailTo() 為 Local Function 由 FullName() 與 Domain() 組合出新的 EmailTo()
這就是所謂的 Function Composition
Function Composition 重複使用性高,程式碼必須『由右而左』
一般人『由左至右』的閱讀習慣,改用 Function Pipeline
將 Name() 與 Domain() 的第一個參數都改加上 this,變成為 Extension Method
原本的 EmailTo() Local Function 就不需要了
只要將 User new 後,直接用 FullName() 與 Domain(),維持了『由左至右』的閱讀習慣
只要將第一個參數加上 this 修飾成為 Extenstion Method 後,
就可由 Function Composition 改成 Function Pipeline 風格
Function Composition 與 Function Pipeline 講的是同一件事情,
只是 Function Composition 採用 由右至左,
而 Function Pipeline 符合閱讀習慣,採用 由左至右
Funciton Compostion 與 Function Pipeline 是 FP 關鍵部分,
以前總以為 C# 沒有支援,
因此無法使用 C# 寫 FP,
有了 Extension Method,
C# 就能很輕鬆的實踐 FP
var john = new User("John", "Doe");
string EmailTo(User u) => Domain(FullName(u));
var email = EmailTo(john);
Console.WriteLine(email);
// jodo@gmail.com (姓 2 碼 + 名 2 碼 +
gmail.com)
EmailFor() 能根據 User 的 姓 與 名 自動產生 email
string EmailTo(User u) => Domain(FullName(u));
EmailTo() 為 Local Function 由 FullName() 與 Domain() 組合出新的 EmailTo()
這就是所謂的 Function Composition
Function Composition 重複使用性高,程式碼必須『由右而左』
一般人『由左至右』的閱讀習慣,改用 Function Pipeline
namespace ConsoleApp
{
public static class Email
{
public static string FullName(this User u) => ShortName(u.FirstName) + CutName(u.LastName);
public static string Domain(this string localPart) => $"{localPart}@gmail.com";
private static string ShortName(string s) => s.Substring(0, 2).ToLower();
}
}
將 Name() 與 Domain() 的第一個參數都改加上 this,變成為 Extension Method
namespace ConsoleApp
{
internal static class Program
{
private static void Main()
{
var email =
new User("John", "Doe")
.FullName()
.Domain();
Console.WriteLine(email);
}
}
}
原本的 EmailTo() Local Function 就不需要了
只要將 User new 後,直接用 FullName() 與 Domain(),維持了『由左至右』的閱讀習慣
只要將第一個參數加上 this 修飾成為 Extenstion Method 後,
就可由 Function Composition 改成 Function Pipeline 風格
Function Composition 與 Function Pipeline 講的是同一件事情,
只是 Function Composition 採用 由右至左,
而 Function Pipeline 符合閱讀習慣,採用 由左至右
Funciton Compostion 與 Function Pipeline 是 FP 關鍵部分,
以前總以為 C# 沒有支援,
因此無法使用 C# 寫 FP,
有了 Extension Method,
C# 就能很輕鬆的實踐 FP
Extension Method
目的:
讓我們在不修改原始程式,為類別增加新函式。
Enumerable.Range() 產生 1、2、3
Select() 2、4、6
ForEach() 列印在畫面上
因為 List 才有 ForEach()
所以先 ToList()
再 ForEach()
這邊可以利用 Extension Method
幫 IEnumerable 打造一個 ForEach()
整理一下
第一、第一個參數 this IEnumerable 特別加了 this 且 class 或 interface
第二、Extension Method 必須都為 static method
讓我們在不修改原始程式,為類別增加新函式。
Enumerable.Range(1, 3)
.Select(x => x * 2)
.ToList()
.ForEach(x => Console.WriteLine(x.ToString()));
Enumerable.Range() 產生 1、2、3
Select() 2、4、6
ForEach() 列印在畫面上
因為 List 才有 ForEach()
所以先 ToList()
再 ForEach()
這邊可以利用 Extension Method
幫 IEnumerable 打造一個 ForEach()
namespace ConsoleApp
{
public static class Extensions
{
internal static void ForEach<t>(this IEnumerable<t> source, Action<t> action)
{
foreach (T element in source)
action(element);
}
}
}
整理一下
第一、第一個參數 this IEnumerable
第二、Extension Method 必須都為 static method
Enumerable
.Range(1, 3)
.Select(x => x * 2)
.ForEach(x => Console.WriteLine(x.ToString()));
用了
Extension Method 後這樣就能拿掉 ToList()
設計模式 AdpaterPattern 轉接器模式
情境:
目前已經有讀取資料的類別了
要設計一個讀取資料類別支援 Json 格式
1.目前已經有一個讀取資料的方法了
2.設計一個讀取資料的介面
3.繼承這個 IReadData 介面
4.要讓 FileReader 共享 IReadData 介面 這時候轉接器模式就可以上場了
總結:
雖然 FileReader 在 FileAdapter 內
但是外部看起來 WebReader 與 FileAdapter 同樣繼承 IReadData 介面
目前已經有讀取資料的類別了
要設計一個讀取資料類別支援 Json 格式
1.目前已經有一個讀取資料的方法了
public class FileReader
{
public string Read(string parameter)
{
string result = string.Empty;
//實作硬碟讀取
return result;
}
}
2.設計一個讀取資料的介面
public interface IReadData
{
string GetJsonData(string parameter);
}
3.繼承這個 IReadData 介面
///
/// 從網路上讀取要的資料
///
public class WebReader : IReadData
{
public string GetJsonData(string parameter)
{
string result = string.Empty;
//實作網路讀取
return result;
}
}
4.要讓 FileReader 共享 IReadData 介面 這時候轉接器模式就可以上場了
public class FileAdapter : IReadData
{
public string GetJsonData(string parameter)
{
var reader = new FileReader();
return reader.Read(parameter);
}
}
總結:
雖然 FileReader 在 FileAdapter 內
但是外部看起來 WebReader 與 FileAdapter 同樣繼承 IReadData 介面
訂閱:
文章 (Atom)
Visual Studio 2017/2019 推薦的擴充功能與更新
參考文章: 覺得 Google 的 Blogger 不太順手?透過 HTML 的 iframe 移花接木 HackMD
-
把程式的捷徑放在下列目錄內: C:\Users\使用者帳號\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup 每次開機便會自動開啟你的程式
-
在「設定」中輸入 editor.fontsize 如下圖框內調整字體大小 PS、目前不支援Ctrl + mouse scroll up/down 調整字體大小 Ctrl + 放大字體 Ctrl - 縮小字體