簡體   English   中英

獲取屬性修飾屬性的值

[英]Get value of an Attribute-decorated property

我想在課堂上做一些驗證,所以我想我可以使用屬性。 像這樣:

public class someClass
{
    [Lenght(200)]
    public string someStr { get; set; }
}
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
sealed class Lenght  : Attribute
{
    public Lenght(int Lenght)
    {
         //some code   
    }
}

但我知道我不能這樣做,因為這不是屬性的工作方式。 而且,如果有辦法,它會使用我想要避免的某種重反射和kludges。

我想要做的驗證是這樣的:

public class someClass
{

    public string someStr
    {
        get
        {
            return _someStr;
        }
        set
        {
            if (value.Length > 200)
            {
                throw new Exception("Max Length is 200!");
            }
            else _someStr = value;
        }
    }
    private string _someStr { get; set; }
}

但我想更快地完成它,沒有所有這些代碼。 我想要與使用屬性一樣快。

我有辦法做到這一點嗎?

屬性的目的是將關於程序集,類型,成員,參數等的元數據聲明到其他組件,工具,編譯器等。當然,你可以做你所要求的,但這將涉及反思自己哪個要像在第二個例子中那樣斷言價值,還有很長的路要走。

您應該考慮的是一個驗證框架,其中包含所有這些內容,並允許您單獨和外部驗證。

有許多驗證框架可供選擇。 我最喜歡的兩個流行的是FluentValidation和Enterprise Library的Validation Application Block

另一方面,也許你只是在尋找一個好的Guard類或Code Contracts 這些用於與驗證不同的目的(參見合同設計 )。 你可以想象將屬性(我建議重用數據注釋 )與一些面向方面的編程相結合,以便以聲明方式為你完成保護(參見PostSharp )。 然而,這可能只是炫耀:)。

您可以創建一個將該字段作為ref參數的方法:

public static void SetWithMaxLength(ref string field, string value, int maxLength)
{
    if(value.Length > maxLength) throw new Exception("Max length is " + maxLength);
    field = value;
}

然后你可以把你的二傳手寫成:

set
{
    SetWithMaxLength(ref this._someStr, value, 200);
}

通常你不會用屬性做這樣的事情,但它是可能的,雖然不值得推薦。 使用風險自負:)(如果屬性沒有使用LengthAttribute修飾,你會放松地獄:))

    public interface AttributeValidator
    {
        void CheckOk(object value);
    }

    public class LenghtAttribute : Attribute, AttributeValidator
    {
        public int MaxLength { get; private set; }
        public LenghtAttribute(int lenght)
        {
            this.MaxLength = lenght;
        }

        public void CheckOk(object value)
        {
            var str = value as string;
            if (str != value)
                throw new Exception("Not a string!");

            if (str != null && str.Length > MaxLength)
                throw new Exception("To long!");
        }
    }

    public class DoesNotContain : Attribute, AttributeValidator
    {
        public string Chars { get; private set; }
        public DoesNotContain(string chars)
        {
            this.Chars = chars;
        }

        public void CheckOk(object value)
        {
            var str = value as string;
            if (str != value)
                throw new Exception("Not a string!");

            if (str != null && Chars.Any(c => str.Contains(c)))
                throw new Exception("Contains forbidden character!");
        }
    }

    public class SomeClass
    {
        private string _someString;

        [Lenght(200)]
        [DoesNotContain("$#2")]
        public string SomeString
        {
            get { return _someString; }
            set
            {
                Utils.Validate("SomeString", this, value);
                _someString = value;
            }
        }
    }

    public static class Utils
    {
        public static void Validate(string property, object instance, string value)
        {
            var validators = instance.GetType().GetProperty(property)
                .GetCustomAttributes(false).OfType<AttributeValidator>();

            foreach (var validator in validators)
                validator.CheckOk(value);
        }
    }

編輯我擴展了這個例子。 仍然是一個可怕的解決方案,但它的確有效。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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