有一个C#types代表一个整数范围?

我有一个需要存储一个整数范围。 C#4.0中是否有现有的types?

当然,我可以写我自己的类, int Fromint To属性,并build立在适当的逻辑,以确保From <= To 。 但如果一个types已经存在,我当然宁愿使用它。

我发现最好的推出自己的。 有些人使用Tuple s或Point s,但最后你希望你的Range是广泛的,并提供一些与Range有关的方便的方法。 这也是最好的,如果通用(如果你需要一系列的Double或一些自定义类的范围?)例如:

 /// <summary>The Range class.</summary> /// <typeparam name="T">Generic parameter.</typeparam> public class Range<T> where T : IComparable<T> { /// <summary>Minimum value of the range.</summary> public T Minimum { get; set; } /// <summary>Maximum value of the range.</summary> public T Maximum { get; set; } /// <summary>Presents the Range in readable format.</summary> /// <returns>String representation of the Range</returns> public override string ToString() { return string.Format("[{0} - {1}]", this.Minimum, this.Maximum); } /// <summary>Determines if the range is valid.</summary> /// <returns>True if range is valid, else false</returns> public bool IsValid() { return this.Minimum.CompareTo(this.Maximum) <= 0; } /// <summary>Determines if the provided value is inside the range.</summary> /// <param name="value">The value to test</param> /// <returns>True if the value is inside Range, else false</returns> public bool ContainsValue(T value) { return (this.Minimum.CompareTo(value) <= 0) && (value.CompareTo(this.Maximum) <= 0); } /// <summary>Determines if this Range is inside the bounds of another range.</summary> /// <param name="Range">The parent range to test on</param> /// <returns>True if range is inclusive, else false</returns> public bool IsInsideRange(Range<T> range) { return this.IsValid() && range.IsValid() && range.ContainsValue(this.Minimum) && range.ContainsValue(this.Maximum); } /// <summary>Determines if another range is inside the bounds of this range.</summary> /// <param name="Range">The child range to test</param> /// <returns>True if range is inside, else false</returns> public bool ContainsRange(Range<T> range) { return this.IsValid() && range.IsValid() && this.ContainsValue(range.Minimum) && this.ContainsValue(range.Maximum); } } 

适用于C#3.0:

 IEnumerable<int> myRange = Enumerable.Range(1, 10); 

编辑请记住:

  • 没有(即时)性能打击 – 这是Linq,所以执行被延期。
  • 有像MinMax这样的方法已经可用了。
  • IEnumerable也暴露了ContainsIntersectUnion – 所以不仅可以查询范围,还可以将它们组合起来
  • 有人已经使用这个表示范围(而不是简单地枚举一个整数集合)。

当然,如果通过“ 存储 ”OP仅担心数据持久性 (而不是数据表示 ),则可以使用具有两个整数字段的简单DTO。

不过,他问“C#4.0中是否有现有的types?” – 我相信答案是肯定的 ,这就是所谓的IEnumerable<int>

编辑2也请记住, Enumerable.Range可能会有非常糟糕的performance。

这可能是什么麻烦大部分这个答案downvoters:有useuse其中Enumerable.Range不是一个实际的select。

不过,我认为还应该考虑以下几点:

  1. 这在语义上是一种表示整数范围的合理方式。
  2. 它可以用于小范围而没有任何明显的性能损失。
  3. 性能问题是偶然的 ,这意味着完全可以返回一个可以查询的IEnumerable<int> ,而不需要迭代整个范围。

关于第三项, 这个库实现了一个Sequence.Create扩展方法。 它的工作方式与Enumerable.Range类似,也返回一个IEnumerable<int> ,但它应该更有效率。

我只写了一小段可能对某人有帮助的课程:

  public class Range { public static List<int> range(int a, int b) { List<int> result = new List<int>(); for(int i = a; i <= b; i++) { result.Add(i); } return result; } public static int[] Understand(string input) { return understand(input).ToArray(); } public static List<int> understand(string input) { List<int> result = new List<int>(); string[] lines = input.Split(new char[] {';', ','}); foreach (string line in lines) { try { int temp = Int32.Parse(line); result.Add(temp); } catch { string[] temp = line.Split(new char[] { '-' }); int a = Int32.Parse(temp[0]); int b = Int32.Parse(temp[1]); result.AddRange(range(a, b).AsEnumerable()); } } return result; } } 

那么你只需要打电话:

 Range.understand("1,5-9,14;16,17;20-24") 

结果如下所示:

 List<int> [0]: 1 [1]: 5 [2]: 6 [3]: 7 [4]: 8 [5]: 9 [6]: 14 [7]: 16 [8]: 17 [9]: 20 [10]: 21 [11]: 22 [12]: 23 [13]: 24 

由于我在C#中也缺less间隔,我实现了一个完全通用的Interval类 ,它甚至可以处理更复杂types的间隔,例如两个DateTime之间的时间间隔, TimeSpan在计算时间间隔。

一个用例,其中一个GUI元素表示一个时间间隔:

 // Mockup of a GUI element and mouse position. var timeBar = new { X = 100, Width = 200 }; int mouseX = 180; // Find out which date on the time bar the mouse is positioned on, // assuming it represents whole of 2014. var timeRepresentation = new Interval<int>( timeBar.X, timeBar.X + timeBar.Width ); DateTime start = new DateTime( 2014, 1, 1 ); DateTime end = new DateTime( 2014, 12, 31 ); var thisYear = new Interval<DateTime, TimeSpan>( start, end ); DateTime hoverOver = timeRepresentation.Map( mouseX, thisYear ); // If the user clicks, zoom in to this position. double zoomLevel = 0.5; double zoomInAt = thisYear.GetPercentageFor( hoverOver ); Interval<DateTime, TimeSpan> zoomed = thisYear.Scale( zoomLevel, zoomInAt ); // Iterate over the interval, eg draw labels. zoomed.EveryStepOf( TimeSpan.FromDays( 1 ), d => DrawLabel( d ) ); 

有关支持的function的更广泛的表示, 请查看unit testing 。

在它的覆盖下,它使用expression式树来编译运行时的types操作符操作 ,这些操作符被caching起来,所以只有在初始化types的时候才会有成本。

改进@ andrius-naruševičius非常有用的答案,使其更习惯和容易定制

 /// <summary> /// http://stackoverflow.com/questions/5343006/is-there-ac-sharp-type-for-representing-an-integer-range /// </summary> public class Range { readonly static char[] Separators = {','}; public static List<int> Explode(int from, int to) { return Enumerable.Range(from, (to-from)+1).ToList(); } public static List<int> Interpret(string input) { var result = new List<int>(); var values = input.Split(Separators); string rangePattern = @"(?<range>(?<from>\d+)-(?<to>\d+))"; var regex = new Regex(rangePattern); foreach (string value in values) { var match = regex.Match(value); if (match.Success) { var from = Parse(match.Groups["from"].Value); var to = Parse(match.Groups["to"].Value); result.AddRange(Explode(from, to)); } else { result.Add(Parse(value)); } } return result; } /// <summary> /// Split this out to allow custom throw etc /// </summary> private static int Parse(string value) { int output; var ok = int.TryParse(value, out output); if (!ok) throw new FormatException($"Failed to parse '{value}' as an integer"); return output; } } 

和testing:

  [Test] public void ExplodeRange() { var output = Range.Explode(5, 9); Assert.AreEqual(5, output.Count); Assert.AreEqual(5, output[0]); Assert.AreEqual(6, output[1]); Assert.AreEqual(7, output[2]); Assert.AreEqual(8, output[3]); Assert.AreEqual(9, output[4]); } [Test] public void ExplodeSingle() { var output = Range.Explode(1, 1); Assert.AreEqual(1, output.Count); Assert.AreEqual(1, output[0]); } [Test] public void InterpretSimple() { var output = Range.Interpret("50"); Assert.AreEqual(1, output.Count); Assert.AreEqual(50, output[0]); } [Test] public void InterpretComplex() { var output = Range.Interpret("1,5-9,14,16,17,20-24"); Assert.AreEqual(14, output.Count); Assert.AreEqual(1, output[0]); Assert.AreEqual(5, output[1]); Assert.AreEqual(6, output[2]); Assert.AreEqual(7, output[3]); Assert.AreEqual(8, output[4]); Assert.AreEqual(9, output[5]); Assert.AreEqual(14, output[6]); Assert.AreEqual(16, output[7]); Assert.AreEqual(17, output[8]); Assert.AreEqual(20, output[9]); Assert.AreEqual(21, output[10]); Assert.AreEqual(22, output[11]); Assert.AreEqual(23, output[12]); Assert.AreEqual(24, output[13]); } [ExpectedException(typeof (FormatException))] [Test] public void InterpretBad() { Range.Interpret("powdered toast man"); } 

写一个这样的扩展方法

  public static class NumericExtentions { public static bool InRange(this int value, int from, int to) { if (value >= from && value <= to) return true; return false; } public static bool InRange(this double value, double from, double to) { if (value >= from && value <= to) return true; return false; } } 

然后优雅地使用它

 if (age.InRange(18, 39)) { //Logic } 

如何结构 ?