[英]Dynamic RegularExpression attribute
我有這個表格,其中有一個郵政編碼字段,在我的ViewModel中,它看起來像這樣:
[RegularExpression(@"^\d{5}(-\d{4})?$")]
public string PostalCode { get; set; }
該正則表達式接受5位數的郵政編碼,但現在我需要支持使用8位,4位或6位郵政編碼的其他國家/地區。
我在數據庫中有這些自定義正則表達式,但我不能以這種方式將非靜態變量傳遞給屬性:
[RegularExpression(MyCustomRegex)]
public string PostalCode { get; set; }
我能做什么? 我嘗試創建自定義屬性,但在某些時候我需要傳遞一個非靜態參數,這是不可能的。
我應該使用反射嗎? 有更干凈的方式嗎?
更好的方法是將屬性與正則表達式分離。
public class PostalCodeAttribute : Attribute
{
public string Country { get; set; }
}
public interface IPostalCodeModel
{
string PostalCode { get; }
}
public class UsModel : IPostalCodeModel
{
[PostalCode(Country = "en-US")]
public string PostalCode { get; set; }
}
public class GbModel : IPostalCodeModel
{
[PostalCode(Country = "en-GB")]
public string PostalCode { get; set; }
}
驗證器:
public class PostalCodeValidator
{
private readonly IRegularExpressionService _regularExpressionService;
public PostalCodeValidator(IRegularExpressionService regularExpressionService)
{
_regularExpressionService = regularExpressionService;
}
public bool IsValid(IPostalCodeModel model)
{
var postalCodeProperty = model.GetType().GetProperty("PostalCode");
var attribute = postalCodeProperty.GetCustomAttribute(typeof(PostalCodeAttribute)) as PostalCodeAttribute;
// Model doesn't implement PostalCodeAttribute
if(attribute == null) return true;
return ValidatePostalCode(_regularExpressionService, model, attribute.Country);
}
private static bool ValidatePostalCode(
IRegularExpressionService regularExpressionService,
IPostalCodeModel model,
string country
)
{
var regex = regularExpressionService.GetPostalCodeRegex(country);
return Regex.IsMatch(model.PostalCode, regex);
}
}
如幾個相關問題所示(例如,將類的實例作為參數傳遞給屬性構造函數 中的屬性構造 函數 Lambda表達式 ),只允許編譯時間文字作為屬性的參數。
我確實想到了可能會或可能不會起作用的解決方法。 我們的想法是創建一個自定義屬性類,該類派生自正則表達式屬性,並在構造上執行正則表達式查找並將結果傳遞給其基礎。
免責聲明:我實際上沒有對它進行測試(並且我沒有計划這樣做;-)。
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
public class PostalCodeAttribute : RegularExpressionAttribute
{
private static ConcurrentDictionary<string, Func<string, string>> _resolverDict = new ConcurrentDictionary<string, Func<string, string>>();
private static string Resolve(string source)
{
Func<string, string> resolver = null;
if (!_resolverDict.TryGetValue(source, out resolver))
throw new InvalidOperationException(string.Format("No resolver for {0}", source));
return resolver(source);
}
public static void RegisterResolver(string source, Func<string, string> resolver)
{
_resolverDict.AddOrUpdate(source, resolver, (s, c) => resolver);
}
static PostalCodeAttribute()
{
// necessary to enable client side validation
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(PostalCodeAttribute), typeof(RegularExpressionAttributeAdapter));
}
public PostalCodeAttribute(string patternSource)
: base(Resolve(patternSource))
{
}
}
/// ...
public void SomeIntializer()
{
PostalCodeAttribute.RegisterResolver("db_source", (s) => PostalCodeRegularExpressions.LookupFromDatabase());
}
public class SomeClassWithDataValidation
{
[PostalCode("db_source")]
public string PostalCode { get; set; }
}
請注意,只有在實例化任何這些屬性之前完成匹配的解析程序功能的注冊時,這才有效。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.