【问题标题】:MinValue & MaxValue attribute for properties属性的 MinValue 和 MaxValue 属性
【发布时间】:2016-04-25 00:33:53
【问题描述】:

是否可以制作可以限制数字的最小值或最大值的属性。

例子:

[MinValue(1), MaxValue(50)]
public int Size { get; set; }

当我执行Size = -3; 时,Size 的值必须为 1。

我在 Google 中搜索并找不到有关此行为的单个示例,可能是因为无法制作?

我将在属性网格中使用这些属性,因此自动验证会很方便。

目前我这样的解决方法来限制最小值:

    private int size;

    [DefaultValue(8)]
    public int Size
    {
        get
        {
            return size;
        }
        set
        {
            size = Math.Max(value, 1);
        }
    }

所以这就像 MinValue(1)

【问题讨论】:

  • PropertyGrid 类不会帮助您实现这一点,它对您的自定义属性一无所知。编写自定义 TypeConverter 很痛苦。在属性设置器中强制执行范围是一种简单的方法。

标签: c# attributes


【解决方案1】:

虽然可以创建自定义属性,但属性只是它们注释的成员的元数据,不能更改其行为。

因此,您不会使用普通属性获得所需的行为。您需要一些东西来处理这些属性,以实现所需的行为。

看看TypeConverters 的可能性。

【讨论】:

    【解决方案2】:

    您可以通过编写简单的方面来优雅地使用PostSharp 解决这个问题,免费版本就足够了:

    [Serializable]
    class RangeAttribute : LocationInterceptionAspect 
    {
        private int min;
        private int max;
    
        public RangeAttribute(int min, int max)
        {
            this.min = min;
            this.max = max;
        }
    
        public override void OnSetValue(LocationInterceptionArgs args)
        {
            int value = (int)args.Value;
            if (value < min) value = min;
            if (value > max) value = max;            
            args.SetNewValue(value);
        }
    }
    

    然后完全如你所愿:

    class SomeClass
    {
        [Range(1, 50)]
        public int Size { get; set; }
    }
    

    正常使用:

    var c = new SomeClass();
    c.Size = -3;
    Console.Output(c.Size);
    

    将输出 1。

    【讨论】:

    • 不自​​动改变值怎么办,如何通知调用者?我可以抛出一个异常吗?
    【解决方案3】:

    是的,这是可能的。在 MSDN 阅读自定义属性。

    顺便说一句,您已经有一个可以使用的解决方案。 RangeAttribute 允许您为数据字段的值指定数值范围约束。在MSDN 上阅读更多相关信息。

    【讨论】:

    • 我已经检查了 MSDN,没有关于使用属性修改属性的设置值的内容。我还检查了 RangeAttribute,它用于 asp.net 数据控件,当我将它与属性网格一起使用时不会有任何效果。
    • 是的,您似乎不了解属性的用途。 Jordao 在他的回答中解释了这一点。我刚刚就您提出的一个问题发布了一个答案“是否可以创建可以限制数字的最小值或最大值的属性。”。
    • @Jaex 你在哪里看到它只用于asp??
    • @OndrejJanacek 尽管它是“在 msdn 上阅读”,但我为我学到的新东西投票:) 干杯
    • @Noctis 在这里:msdn.microsoft.com/en-us/library/… "System.ComponentModel.DataAnnotations 命名空间提供了用于为 ASP.NET MVC 和 ASP.NET 数据控件定义元数据的属性类。"
    【解决方案4】:

    是的,使用(已经指出的)CustomAttributes 是可能的,但请注意,您将失去自动属性的舒适性 - 因为您需要分别应用。检查某处的属性限制,在这种情况下,适当的位置将是属性的 getter,因此问题的有趣部分是属性的应用。您可以阅读如何访问自定义属性 in this MSDN article

    MaxValue 自定义属性的可能解决方案如下所示:

    // simple class for the example
    public class DataHolder
    {
        private int a;
    
        [MaxValue(10)]
        public int A 
        { 
            get
            {
                var memberInfo = this.GetType().GetMember("A");
                if (memberInfo.Length > 0)
                {
                    // name of property could be retrieved via reflection
                    var mia = this.GetType().GetMember("A")[0];
                    var attributes = System.Attribute.GetCustomAttributes(mia);
                    if (attributes.Length > 0)
                    {
                        // TODO: iterate over all attributes and check attribute name
                        var maxValueAttribute = (MaxValue)attributes[0];
                        if (a > maxValueAttribute.Max) { a = maxValueAttribute.Max; }
                    }
                }
                return a;
            }
            set
            {
                a = value;
            }
        }
    }
    
    
    // max attribute
    public class MaxValue : Attribute
    {
        public int Max;
    
        public MaxValue(int max)
        {
            Max = max;  
        }
    }
    

    示例用法:

    var data = new DataHolder();
    data.A = 12;
    Console.WriteLine(data.A);
    

    创建输出:

    10
    

    MinValue 的代码看起来与 MaxValue 的代码相同,但 if 条件将是 小于 而不是 大于

    【讨论】:

    • 感谢您的努力,但不幸的是在获取属性中使用size = Math.Max(value, 1); 将是更优雅的解决方案。
    • 是的,但这是属性的问题 - 在某些时候和某处需要评估和应用它们,否则如果不使用它们有什么用处。
    • 也许使用propertygrid 继承有可能在设置值时评估属性。但弄清楚这将是太多的工作,所以我将继续使用 Math.Max 解决方案。
    【解决方案5】:

    创建一个扩展

    public static class Extensions
    {
      public static int FixedValue(this int value, int min, int max)
      {
        if (value >= min && value <= max)
          return value;
        else if (value > max)
          return max;
        else if (value < min)
          return min;
        else return 1;
      }
    }
    

    然后:

    private int size;
    public int Size { get { return size.FixedValue(1, 50); }
                      set { size = value.FixedValue(1, 50); } }
    

    【讨论】:

    • 老实说...考虑到向无效属性值添加错误消息的“复杂性”;我觉得@Salvador 的回答只有 1 票很尴尬。我竖起大拇指。 1. 我(终于)理解了扩展。 2.他得到了类似的;比我自己的方法更好。所以是的。竖起大拇指。
    猜你喜欢
    • 1970-01-01
    • 2021-04-10
    • 1970-01-01
    • 2017-03-25
    • 2017-10-03
    • 2018-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多