2013-08-20 82 views
3

我有這樣的形式,其中有一個郵政代碼字段,在我的視圖模型,它看起來是這樣的:動態正則表達式屬性

[RegularExpression(@"^\d{5}(-\d{4})?$")] 
public string PostalCode { get; set; } 

這正則表達式接受5位郵政編碼,但現在我需要支持其他國家他們在那裏使用8位,4位或6位數的郵政編碼。

我在數據庫中的那些自定義的正則表達式,但我不能通過非靜態變量的屬性這樣:

[RegularExpression(MyCustomRegex)] 
public string PostalCode { get; set; } 

我能做些什麼?我嘗試創建一個自定義屬性,但在某些時候我需要傳遞一個非靜態參數,這是不可能的。

我應該使用反射嗎?有更清潔的方法嗎?

回答

1

更好的方法可能是從正則表達式中分離屬性。

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); 
    } 
} 
+0

最後,我終於找到了一種方法來獲取我所需要的所有數據,而無需將其作爲參數傳遞,但如果我無法做到這一點,我認爲這將是最佳選擇。 –

+0

嗨,我知道它現在回來了,但我有確切的相同的問題。是否有可能分享你上面提到的解決方案?非常感謝你 – duongthaiha

0

作爲幾個相關問題(例如Pass instance of Class as parameter to Attribute constructorLambda expression in attribute constructor)表明只編譯時間文字被允許作爲一個屬性參數。

我的確想到了一個解決方法,可能會或可能無法正常工作。這個想法是創建一個自定義的屬性類,它派生自正則表達式屬性,並執行構造的正則表達式查找並將結果傳遞給它的基礎。

免責聲明:我沒有真正測試過它(而且我不打算這麼做;-)。

[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; } 
} 

注意,這隻會工作,如果匹配解析函數的註冊這些屬性初始化之前完成。