1

クラスでいくつかの検証を行いたいので、属性を使用できると思いました。このような:

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

しかし、これは属性が機能する方法ではないため、私はそれを行うことができないことを知っています。そして、方法があれば、それは私が避けたいある種の重い反射とクラッジを使用するでしょう。

私がやりたい検証は次のようなものです。

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

しかし、私はこのコードをすべて使わずに、もっと速くやりたいと思っています。属性を使用するのと同じくらい速くしたい。

私がそれをすることができる方法はありますか?

4

3 に答える 3

1

通常、属性を使用してこのようなことを行うことはありませんが、推奨されませんが、可能です。ご自身の責任で使用してください:)(プロパティが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);
        }
    }

編集私は例を拡張しました。それでも恐ろしい解決策ですが、それは機能します。

于 2012-11-06T13:14:03.103 に答える
1

属性の目的は、アセンブリ、タイプ、メンバー、パラメーターなどに関するメタデータを他のコンポーネント、ツール、コンパイラーなどに宣言することです。確かに、あなたはあなたが求めていることを行うことができますが、それはそれ自体に反映することを含みます2番目の例のように、値をアサートするだけの長い道のりです。

代わりに検討する必要があるのは、これらすべてのものが組み込まれている検証フレームワークであり、個別に外部で検証することができます。

選択できる検証フレームワークは多数あります。私の頭の中で人気のある2つは、FluentValidationとEnterpriseLibraryのValidationApplicationBlockです。

一方、おそらくあなたはちょうど良いガードクラスまたはコードコントラクトを探しています。これらは検証とは異なる目的を果たします(契約による設計を参照)。おそらく、属性(データアノテーションを再利用することをお勧めします)をアスペクト指向プログラミングと組み合わせて、宣言型のガード作業を行うことができます(PostSharpを参照)。しかし、それはおそらくただ誇示しているでしょう:)。

于 2012-11-06T12:59:31.460 に答える
1

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);
}
于 2012-11-06T12:59:40.450 に答える