PostSharp - Custom Contract

PostSharp 內建的 Contracts 能支援我們做些常見的檢查,若是內建的無法滿足,我們也可以自行擴建 Contract。


擴建時要先確保 PostSharp.Patterns.Model 的引用已加入專案中,若無可透過 NuGet 將套件安裝起來。


接著建立個繼承自 LocationContractAttribute 的 Contract 類別,LocationContractAttribute 會提供我們建立 Contract Attribute 所需的基本功能,像是 CreateArgumentException、CreateArgumentNullException、CreateArgumentOutOfRangeException、及 ErrorMessage 等。


並實作 ILocationValidationAspect\ ,在 ValudateValue 方法中撰寫自己的判斷邏輯,當不符合規範時叫用繼承自 LocationContractAttribute 的方法拋出例外即可。


筆者這邊以建立個 RegexMatch 的 Contract 為例,讓使用上可以帶上不同的正規表示式進行驗證。建立個繼承自 LocationContractAttribute 的類別 ,因為這邊要檢查的參數型態為字串,故還要實作 ILocationValidationAspect\ 介面,在 ValudateValue 方法中會去判斷值是否符合我們設定的 Pattern,若否則叫用 CreateArgumentException 丟出例外。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class RegexMatchAttribute : LocationContractAttribute , ILocationValidationAspect <string>
{
public String Pattern { get; set; }

public RegexMatchAttribute(string pattern)
: base()
{
this.Pattern = pattern;
}

public Exception ValidateValue(string value, string locationName, PostSharp.Reflection.LocationKind locationKind)
{
if (Regex .IsMatch(value, this.Pattern))
return null ;

return this .CreateArgumentException(value, locationName, locationKind);
}
}


寫完後就可以實際套用到程式中去做參數的驗證。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
namespace ConsoleApplication32
{
class Program
{
static void Main(string[] args)
{
var blog = new Blog( "LevelUp", "http://larrynung.github.io" );
blog = new Blog ("!@##&", "http://larrynung.github.io" );
}
}

public class Blog
{
public string Name { get; set; }
public string Url { get; set; }

public Blog([RegexMatch (@"[\w\d]+")] string name, string url)
{
this.Name = name;
this.Url = url;
}
}
}


運行結果如下,當代入不符合 Pattern 的參數時就會丟出例外。


這邊若有需要,我們也可以用上面提到的 ErrorMessage 屬性將錯誤訊息進行客製。