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

属性的目的是向其他组件、工具、编译器等声明有关程序集、类型、成员、参数等的元数据。当然,您可以按照您的要求进行操作,但这将涉及对自身进行反思像在第二个示例中那样断言值还有很长的路要走。

相反,您应该考虑的是一个验证框架,它为您内置了所有这些东西,并允许您单独和外部验证。

有许多验证框架可供选择。我脑海中最流行的两个是FluentValidation和 Enterprise Library 的Validation Application Block

另一方面,也许您只是在寻找一个好的Guard类或Code Contracts。这些服务的目的与验证不同(请参阅按合同设计)。您可以想象将属性(我建议重用Data Annotations)与一些面向方面的编程结合起来,以声明方式为您完成保护工作(请参阅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 回答
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 回答