網頁

2010年8月30日 星期一

Guid TryParse

日前在專案執行上突然有個需求,就是要對輸入的資料做Guid格式的驗證,
一開始就下意識去找Guid下的TryParse方法,這個時候才發現 .NET 3.5(2.0) 的Guid是沒有TryParse方法…
細查下去才知道,Guid的TryParse與Parse方法在 .NET 4.0才新加入(小弟真是才疏學淺…汗顏…),
之前經常使用Guid,卻甚少對Guid的格式驗證稍加留意。


Guid,Globally Unique Identifier 全域唯一識別項
Wiki : Globally unique identifier

Guid 結構
GUID 是一個 128 位元的整數 (16 位元組),可以在需要唯一識別項時用於所有電腦和網路。這種識別項被複製的可能性非常低。

在程式設計中會常常在編號的使用上,因為使用GUID不會有重複編號的問題存在(不是不會有,而是機率相當低),
所以在類別設計時,在類別的ID (Primary Key) 屬性上,我會優先使用GUID來做為Class中主鍵資料的型別,
而在SQL Server的Table 欄位的型別就是使用uniqueidentifier

在 .NET Framework 2.0 版本並沒有提供 TryParse, Parse 的Method,
如果時常需要使用到Guid的檢測時,就必須另外編寫TryParse的方法,以利日後的程式編寫。

.NET Framework 2.0 的GUID成員之公用方法
image

Guid還有幾種格式的區別,分別為:"N"、"D"、"B"、"P"、"X"

以下顯示 format 參數已接受的格式規範表示。
0"代表一個數字,連字號 ("-")、括號 ("{","}"),及括號 ("(",")") 如下所示。

N
32 位數字:00000000000000000000000000000000
D
以連字號分隔的 32 位數字:00000000-0000-0000-0000-000000000000
B
以連字號分隔並以大括號括起來的 32 位數字:{00000000-0000-0000-0000-000000000000}
P
以連字號分隔並以括號括起來的 32 位數字:(00000000-0000-0000-0000-000000000000)
X
括號中包含四個十六進位值,其中第四個值是八個十六進位值的子集,同樣包含在括號中:
{0x00000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}

先來看看在4.0之前對GUID進行TryParse的方法
Reference by: http://connect.microsoft.com/VisualStudio/feedback/details/94072/guid-tryparse
#region -- GuidTryParse --
 
/// <summary>
/// GUIDs the try parse.
/// </summary>
/// <param name="candidate">The candidate.</param>
/// <param name="output">The output.</param>
/// <returns></returns>
public static bool GuidTryParse(string candidate, out Guid output)
{
if (candidate == null) throw new ArgumentNullException("s");
 
Regex format = new Regex(string.Concat(
"^[A-Fa-f0-9]{32}$|",
"^({|\\()?[A-Fa-f0-9]{8}-([A-Fa-f0-9]{4}-){3}[A-Fa-f0-9]{12}(}|\\))?$|",
"^({)?[0xA-Fa-f0-9]{3,10}(, {0,1}[0xA-Fa-f0-9]{3,6}){2}, {0,1}({)([0xA-Fa-f0-9]{3,4}, {0,1}){7}[0xA-Fa-f0-9]{3,4}(}})$"
));
 
Match match = format.Match(candidate);
output = (match.Success) ? new Guid(candidate) : Guid.Empty;
return match.Success;
}
 
#endregion


實際的使用
image

程式碼


protected void button1_Click(object sender, EventArgs e)
{
// TryParse Correct GUID
System.Guid check = System.Guid.NewGuid();
bool result = Test.GuidTryParse(text1.Text.Trim(), out check);
label1.Text = result.ToString();
}
 
protected void button2_Click(object sender, EventArgs e)
{
// TryParse Wrong GUID
System.Guid check = System.Guid.NewGuid();
bool result = Test.GuidTryParse(text2.Text.Trim(), out check);
label2.Text = result.ToString();
}

上面是 .NET Framework 3.5 以前的方法

而在 .NET Framework 4.0 就已經將Parse, TryParse等方法加入

.NET Framework 4.0 的GUID成員之公用方法

image

上面的各種方法成員中,可以看到四個方法:Parse、ParseExact、TryParse、TryParseExact,

而ParseExact與TryParseExact則是可以讓我們指定哪一種 Guid的格式。


直接看 .NET 4.0下Guid的TryParse與TryParseExact的單元測試

[TestMethod]
public void Guid_TryParse_Test()
{
System.Guid testGuid1 = System.Guid.NewGuid();
string guidB = testGuid1.ToString("B");
 
Assert.IsTrue(System.Guid.TryParse(guidB, out testGuid1));
Assert.IsTrue(System.Guid.TryParseExact(guidB, "B", out testGuid1));
Assert.IsFalse(System.Guid.TryParseExact(guidB, "X", out testGuid1));
 
System.Guid testGuid2 = System.Guid.Parse(guidB);
string guidX = testGuid2.ToString("X");
 
Assert.IsTrue(System.Guid.TryParse(guidX, out testGuid2));
Assert.IsTrue(System.Guid.TryParseExact(guidX, "X", out testGuid2));
Assert.IsFalse(System.Guid.TryParseExact(guidX, "B", out testGuid2));
} 

或許有人會說…怎麼不用以下的方法來解決呢?

private bool IsGuid(string source)
{
if (string.IsNullOrEmpty(source))
{
return false;
}
try 
{
System.Guid test = new System.Guid(source);
return true;
}
catch
{
return false;
}
}

這是因為「try … catch …」,雖然在Catch區段才會對效能產生影響,雖然效能的影響不是很嚴重,

但是濫用try catch來做檢測,實在不是一個認知正確的coding作為,

應該是去用正確的方式去做對的事,而不能只是要將事情去做對而已。



Jeff隨手記 - Try Catch Finally概述

黑暗執行緒 - Try Catch Block是否會影響效能?



所以…

如果在資料主鍵沒有特殊需求,否則建議使用Guid來做為主鍵的型別,

而且在於資料安全上會比一般用int然後自動增值的主鍵要來得高,

使用 int自動增值的主鍵,容易引來有心人士對系統的「特別關注」,因為數字資料實在是太容易做改變了。



延伸閱讀:

The Gospel of the GUID

Will 保哥 - 深入瞭解 GUID 與為什麼要用 GUID

MSDN : 使用 GUID




沒有留言:

張貼留言