簡體   English   中英

動態RegularExpression屬性

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM