2013-08-20 179 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; } 
} 

注意,这只会工作,如果匹配解析函数的注册这些属性初始化之前完成。