1

モデル内の他のいくつかのプロパティの値に応じて、プロパティに値が含まれていることを検証する If-IsRequired カスタム属性を作成しました。この属性をできるだけ多くの状況に適用したいので、開発者がこの属性を利用して、一致するパラメーターを無数に指定できるオプションを許可したいと考えています。最後に、すべてのパラメーターが正しく一致するように強制できるようにしたいと考えています。

ここまで書いてきました。私は現在、文字列の配列を使用していますが、動作できなかったある種のコレクションを使用できれば幸いです。さらに、現在の属性定義をサポートし、比較演算子を含む新しいオーバーロードを作成する必要があります。これにより、すべての比較が等号で行われると仮定する元の定義に加えて、より小さい、より大きい、および等しくない比較を行うことができます。

    /// <summary>
    /// A custom attribute that checks the value of other properties passed to it in order to
    /// determine if the property this attribute is bound to should be required.
    /// </summary>
    [AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
    public class IsPropertyRequiredAttribute : ValidationAttribute
    {
        private const string DefaultErrorMessage = "{0} is required.";

        public string[] _selectionContextNames { get; private set; }
        public string[] _expectedValues { get; private set; }

        /// <summary>
        /// Creates a new instance of the IsPropertyRequriedAttribute.
        /// </summary>
        /// <param name="SelectionContextNames">The name of the other property in the view model to check the value of.</param>
        /// <param name="ExpectedValues">The expected value of the other property in the view model in order to determine if the current property the attribute is bound to should be required.</param>
        public IsPropertyRequiredAttribute(string[] SelectionContextNames, string ExpectedValues)
            : base(DefaultErrorMessage)
        {

            _selectionContextNames = SelectionContextNames;
            _expectedValues = ExpectedValues;
        }

        public override bool IsValid(object value)
        {
            if (_selectionContextNames == null || _expectedValues == null)
            {
                if (_selectionContextNames != null || _expectedValues != null)
                {
                    string paramName;
                    if (_selectionContextNames == null)
                    {
                        paramName = "ExpectedValues";
                    }
                    else
                    {
                        paramName = "SelectionContextNames";
                    }

                    throw new ArgumentException("Key/Value pairs need to match for IsPropertyRequired.", paramName);
                }
            }
            else if (_selectionContextNames.Length != _expectedValues.Length)
            {
                string paramName;
                if (_selectionContextNames.Length < _expectedValues.Length)
                {
                    paramName = "ExpectedValues";
                }
                else
                {
                    paramName = "SelectionContextNames";
                }

                throw new ArgumentException("Parameter element counts need to match for IsPropertyRequired.", paramName);
            }

            bool paramsValid = true;

            if (_selectionContextName!= null)
            {
                for (int i = 0; i < _selectionContextName.Length; i++)
                {
                    string paramValue = HttpContext.Current.Request[_selectionContextName[i]];

                    if (_expectedValue[i] != paramValue)
                    {
                        paramsValid = false;
                    }
                }

                if (paramsValid == true)
                {
                    return (value != null);
                }
                else
                {
                    return true;
                }
            }
            else
            {
                return true;
            }
        }

        public override string FormatErrorMessage(string name)
        {
            return String.Format(DefaultErrorMessage, name);
        }
    }

属性を使用してプロパティを装飾するかどうかは、属性の定義方法によって異なりますが、これは私が現在実装しているものです (これもおそらく改善される可能性があります)。

[IsPropertyRequired(new string[] {"prop1", "prop2", "prop3", "prop4"}, new string[] {"1", "2", "3", "4"})]
public string SomeText { get; set; }

また、次の装飾が行われないように、できる限り防止したいと考えています。

[IsPropertyRequired(new string[] {"prop1", "prop2", "prop3", "prop4", "prop5withoutvalue"}, new string[] {"1", "2", "3", "4"})]
public string SomeOtherText { get; set; }

また、比較演算子をパラメーターとして含む新しいオーバーロードを使用すると、次のようになります。

[IsPropertyRequired(new string[] {"prop1", "prop2", "prop3", "prop4"}, new string[] {"==", ">", "!=", "<="}, new string[] {"1", "2", "3", "4"})]
public string SomeComparisonText { get; set; }
4

1 に答える 1

0

MSDNで説明されているように、.NET の属性は指定できる型が非常に限られています。より複雑なデータを指定する場合は、属性を記述して、より豊富なデータ構造の別の場所を指定することをお勧めします。

たとえば、次の構文の属性を想像してください。

[ValidationRules(typeof(MyValidationRuleInfo, "MyRuleSet")]
public int SomeProperty { get; set; }

...

public static class MyValidationRuleInfo {
    public static Dictionary<string, ValidationRule> MyRuleSet {
        get {
            return new { ... rules go here ... }
        }
}

そして、属性はターゲット クラスのプロパティを検索し、そこにあるすべてのルールを取得します。すべてのルールのすべてのロジックを実装するのはあなた次第ですが、属性スープを避けることができ、扱いにくいデータ構造も避けることができます。

実際、xUnit.NET 単体テスト ライブラリは、ここに示すように、その属性Theoryと属性を使用して同様のことを行います。PropertyData

于 2013-03-13T01:33:28.807 に答える