【问题标题】:Is there a standard class to represent a “range” in .net?.net 中是否有代表“范围”的标准类?
【发布时间】:2012-04-16 10:56:07
【问题描述】:

我们有很多代码,其中包含价格、利润、成本等的“最小值”和“最大值”。目前,它们作为两个参数传递给方法,并且通常具有不同的属性/方法来检索它们。

在过去的几十年中,我已经看到了 101 个自定义类来存储不同代码库中的值范围,在我创建另一个这样的类之前,我希望确认现在的 .NET 框架没有这样的类内置某处。

(如果需要,我知道如何创建自己的课程,但我们已经有太多的轮子了,我无法一时兴起发明另一个)

【问题讨论】:

    标签: .net design-patterns range


    【解决方案1】:

    AFAIK 在.NET 中没有这样的东西。不过,想出一个通用的实现会很有趣。

    构建一个通用的 BCL 质量范围类型需要做很多工作,但它可能看起来像这样:

    public enum RangeBoundaryType
    {
        Inclusive = 0,
        Exclusive
    }
    
    public struct Range<T> : IComparable<Range<T>>, IEquatable<Range<T>>
        where T : struct, IComparable<T>
    {
        public Range(T min, T max) : 
            this(min, RangeBoundaryType.Inclusive, 
                max, RangeBoundaryType.Inclusive)
        {
        }
    
        public Range(T min, RangeBoundaryType minBoundary,
            T max, RangeBoundaryType maxBoundary)
        {
            this.Min = min;
            this.Max = max;
            this.MinBoundary = minBoundary;
            this.MaxBoundary = maxBoundary;
        }
    
        public T Min { get; private set; }
        public T Max { get; private set; }
        public RangeBoundaryType MinBoundary { get; private set; }
        public RangeBoundaryType MaxBoundary { get; private set; }
    
        public bool Contains(Range<T> other)
        {
            // TODO
        }
    
        public bool OverlapsWith(Range<T> other)
        {
            // TODO
        }
    
        public override string ToString()
        {
            return string.Format("Min: {0} {1}, Max: {2} {3}",
                this.Min, this.MinBoundary, this.Max, this.MaxBoundary);
        }
    
        public override int GetHashCode()
        {
            return this.Min.GetHashCode() << 256 ^ this.Max.GetHashCode();
        }
    
        public bool Equals(Range<T> other)
        {
            return
                this.Min.CompareTo(other.Min) == 0 &&
                this.Max.CompareTo(other.Max) == 0 &&
                this.MinBoundary == other.MinBoundary &&
                this.MaxBoundary == other.MaxBoundary;
        }
    
        public static bool operator ==(Range<T> left, Range<T> right)
        {
            return left.Equals(right);
        }
    
        public static bool operator !=(Range<T> left, Range<T> right)
        {
            return !left.Equals(right);
        }
    
        public int CompareTo(Range<T> other)
        {
            if (this.Min.CompareTo(other.Min) != 0)
            {
                return this.Min.CompareTo(other.Min);
            }
    
            if (this.Max.CompareTo(other.Max) != 0)
            {
                this.Max.CompareTo(other.Max);
            }
    
            if (this.MinBoundary != other.MinBoundary)
            {
                return this.MinBoundary.CompareTo(other.Min);
            }
    
            if (this.MaxBoundary != other.MaxBoundary)
            {
                return this.MaxBoundary.CompareTo(other.MaxBoundary);
            }
    
            return 0;
        }
    }
    

    【讨论】:

    • 好吧,我没有对你投反对票,但我不喜欢这里的东西,是强制 T 成为结构吗?为什么会有这样的约束?另一件事是范围本身不应该是结构。当 Struct 占用的内存少于指针时,它是好的(然后它是有效的 - 复制)。这个类显然需要超过 4 或 8 个字节。
    • @dzendras:我同意你的 cmets。这个想法是给类型值类型语义,所以我选择了struct,但这不是必须的。请注意,框架设计指南建议值类型小于 16 字节,因此不是 8 或 4,但范围很容易变成 16 字节或更大,例如在使用 Range&lt;DateTime&gt; 时。
    【解决方案2】:

    没错,在 2020 年之前,C# 或范围的 BCL 中没有内置类。但是,BCL 中有 TimeSpan 用于表示时间跨度,您可以另外与 DateTime 组合以表示时间范围。

    【讨论】:

    • 我也得到了两个无法解释的反对票。很烦人。 +1 我来补偿。
    • 我猜是因为 .Net 实际上有一个,它是 System.Core dll 中的 Enumerable 类,所以它是内置的并且有一些 Range API。
    • @Jason,FCL 中的那个只是一个数字范围,但是当您需要一些基本范围来构建自己的东西时,它就在那里并且非常有用。我猜为什么这个回复得到了几票反对。但是,放下手,这不是我。我只是猜测。
    • @sovemp:不,那是为了在给定范围内生成序列,这与 ADT 范围不同,可以让您测试成员资格等。
    【解决方案3】:

    我已经开始自己制作了。

    public class Range<T> where T : IComparable
    {
        private readonly T start;
    
        private readonly T end;
    
        public Range(T start, T end)
        {
            if (start.CompareTo(end) < 0)
            {
                this.start = start;
                this.end = end;
            }
            else
            {
                this.start = end;
                this.end = start;
            }
        }
    
        public T Start
        {
            get
            {
                return this.start;
            }
        }
    
        public T End
        {
            get
            {
                return this.end;
            }
        }
    
        public static bool Intersect(Range<T> a, Range<T> b)
        {
            return !(b.Start.CompareTo(a.End) > 0 || a.Start.CompareTo(b.End) > 0);
        }
    
        public bool Intersect(Range<T> other)
        {
            return Intersect(this, other);
        }
    }
    

    【讨论】:

      【解决方案4】:

      这只是在 .Net Core 3.0 中发生了变化,请参阅 System.Range
      C# 8 也有language support for creating ranges

      另请参阅“What is Range and Index types in c# 8?”Stackoverflow 问题。

      注意这些仅支持整数范围,不支持双精度或浮点范围。

      【讨论】:

        猜你喜欢
        • 2013-12-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-06-07
        • 2016-08-07
        • 1970-01-01
        相关资源
        最近更新 更多