【问题标题】:Check parameter range on generic types检查泛型类型的参数范围
【发布时间】:2020-03-06 11:04:29
【问题描述】:

有没有办法做类似“string.Compare()”的事情,但对于泛型类型。我想检查一些属性值的范围。
这是我正在做的工作,但它非常难看:

public class SomeClass<T>
{

    public T MinValue { get; set; }
    public T MaxValue { get; set; }

    private T _value;
    public T Value
    {
        get { return _value; }
        set
        {
            _value = value;

            // Restrict range to Min/Max
            if (Comparer<T>.Default.Compare(MaxValue, value) < 0)
                _value = MaxValue;
            if (Comparer<T>.Default.Compare(MinValue, value) > 0)
                _value = MinValue;
        }
    }
}

【问题讨论】:

  • 不,这对我来说看起来不错。这就是 BCL 的作用(请参阅此处左侧的“参考”列表:source.dot.net/#System.Private.CoreLib/src/System/Collections/…
  • 你所拥有的很好,但如果调用者想要指定自定义比较,则可以添加IComparer&lt;T&gt; 类型的可选构造函数参数。 (如果没有指定,您将回退到使用 Comparer&lt;T&gt;.Default 就像您已经这样做。)
  • 你可以在类的顶部引入private IComparer&lt;T&gt; _comparer = Comparer&lt;T&gt;.Default;,并使SomeClass泛型
  • 该类实际上必须已经声明为public class SomeClass&lt;T&gt;,否则OP中的代码将无法编译。我假设 OP 只是忘记了它。
  • @stackMeUp 如果您使用反射,则处理每个属性,询问它是否具有最小-最大类型的数据注释。 stackoverflow.com/questions/7027613/…

标签: c# generics compare range


【解决方案1】:

此代码演示了我在评论中所说的内容。当然,你必须修改它以适应你的精确范式,在比较器中使用它,但这应该足够清楚......

public class Program
    {
        public static void Main(string[] args)
        {
            System.Console.WriteLine("Hello World!");

            TestObject testObject = new TestObject(15);

            TestObject testObject2 = new TestObject(9);

            TestObject testObject3 = new TestObject(31);

            System.Console.ReadLine();
        }
    }

public class TestObject
    {
        [ValidateIntMin(Min = 10)]
        [ValidateIntMax(30)]
        public int SomeInt { get; set; }

        public TestObject(int value)
        {
            SomeInt = value;

            if (!Validator.Validate(this))
            {
                System.Console.WriteLine("Invalid Value assigned: " + value);
            }
            else
            {
                System.Console.WriteLine("" + SomeInt + " was a valid value");
            }

        }
    }

public class ValidateIntMax : Attribute
    {
        public int Max { get; set; }

        public ValidateIntMax(int MaxValue)
        {
            Max = MaxValue;
        }
    }

public class ValidateIntMin: Attribute
    {
        public int Min { get; set; }
    }

public static class Validator
    {
        public static bool Validate<T>(T input) {
            var attrType = typeof(T);
            var properties = attrType.GetProperties();
            bool isValid = true;
            foreach (PropertyInfo propertyInfo in properties)
            {
                var customerMaxValueInt = propertyInfo.GetCustomAttributes(typeof(ValidateIntMax), false).FirstOrDefault();
                var customerMinValueInt = propertyInfo.GetCustomAttributes(typeof(ValidateIntMin), false).FirstOrDefault();

                if (customerMaxValueInt != null)
                {
                    if (propertyInfo.PropertyType == typeof(int))
                    {
                        var currentPropertyInfoBeingTested = (int)propertyInfo.GetValue(input);
                        var currentMaxValueToVerifyAgainst = ((ValidateIntMax)customerMaxValueInt).Max;

                        if (currentPropertyInfoBeingTested > currentMaxValueToVerifyAgainst)
                        {
                            isValid = false;
                        }
                    }
                }

                if (customerMinValueInt != null)
                {
                    if (propertyInfo.PropertyType == typeof(int))
                    {
                        var currentPropertyInfoBeingTested = (int)propertyInfo.GetValue(input);
                        var currentMaxValueToVerifyAgainst = ((ValidateIntMin)customerMinValueInt).Min;

                        if (currentPropertyInfoBeingTested < currentMaxValueToVerifyAgainst)
                        {
                            isValid = false;
                        }
                    }
                }

            }
            return isValid;
        }
    }

应该给出输出:

Hello World!

15 was a valid value

Invalid Value assigned: 9

Invalid Value assigned: 31

当然,您可以为不同类型添加验证等。 这只是为了展示一种完全自定义的设置属性的方式。

不过,我建议您阅读 ValidationAttribute,看看您是否不能使用已实现的功能。

但这只是 PoC 的一部分。

【讨论】:

  • 感谢 Morten Bork,很好的例子。理想情况下,我想要“[ValidateIntMax(T MaxValue)]”,因为在我的情况下,最小/最大值是在运行时定义的,但我认为使用泛型类型是不可能的。
猜你喜欢
  • 1970-01-01
  • 2018-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-06
  • 2020-09-18
  • 2016-10-10
  • 1970-01-01
相关资源
最近更新 更多