我有这个表格,其中有一个邮政编码字段,在我的ViewModel中它看起来像这样:
[RegularExpression(@"^\d{5}(-\d{4})?$")]
public string PostalCode { get; set; }
该正则表达式接受5位数的邮政编码,但现在我需要支持使用8位,4位或6位邮政编码的其他国家/地区。
我在数据库中有这些自定义正则表达式,但我不能以这种方式将非静态变量传递给属性:
[RegularExpression(MyCustomRegex)]
public string PostalCode { get; set; }
我该怎么办?我尝试创建自定义属性,但在某些时候我需要传递一个非静态参数,这是不可能的。
我应该使用反射吗?有更清洁的方式吗?
答案 0 :(得分: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);
}
}
答案 1 :(得分:0)
如几个相关问题所示(例如Pass instance of Class as parameter to Attribute constructor Lambda 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; }
}
请注意,只有在实例化任何这些属性之前完成匹配的解析程序功能的注册时,这才有效。