.NETで範囲と境界線を操作する

翻訳者から。 .NETの範囲(間隔)の主題は、永遠に緑と若者を正当に指します。 フォーラムで寄せられた数百の質問、書かれた多数の記事...これは、Microsoftが最終的にフレームワーククラスライブラリに範囲を操作するメカニズムを導入したときにのみ終了するようです。 そして、これには論理的な説明があります-おそらく、すべてのプログラマーは、遅かれ早かれ、数値、日付、またはその他の値である特定の範囲の値を使用する必要に直面します。 私はそのようなニーズもありましたが、私の自転車は最良の解決策ではないことを思い出して、インターネットを介してJohn Skeetの優れた記事にたどり着きました。



私の本の初版「 C#in Depth 」は、仮想メソッドを使用して範囲内の要素をトラバースする抽象的な汎用Range



クラスを引用しました。 残念ながら、このクラスは特定の境界線のケースを考慮していないため、不完全でした。 ただし、この記事では、範囲を操作するための理想的なクラスの設計についてではなく、どのニュアンスと考慮事項を考慮する必要があるかについて説明します。 私のMiscUtilクラスライブラリには、この記事で説明したほとんどのことを考慮したクラスが含まれていますが、もちろん、このクラスは理想からはほど遠いものです。 一般的に、2008年1月にブログで範囲に関する短い記事を書きましたが、それ以来多くの水が流れ、多くのことを再考し、この記事の形でトピックをより詳細に展開することにしました。





問題の声明



まず、私たちが何をしたいのか、何ができるのかを決めましょう。できるだけ一意にタスクを定式化します。



私たちはすべてを説明しているように見えますが、悪魔は細部に宿っていることを忘れないでください。 また、次のことも考慮する必要があります。



一般的な用語で問題を定式化したので、細かい部分に進むことができます。



詳細



まず、範囲での使用に一般的に有効なタイプについて考えてみましょう。 範囲クラスをジェネリックにし、どちらが大きいか、小さいかを知るために、2つの値を互いに比較できるようにします。 このような制約をタイプT



に適用することでこれを達成できますが、タイプT



IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null «» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .
























































インターフェイスを実装する必要がありますIComparable. , , C# — IComparable. , , . , , (reversing) , . , .



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null «» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .
























































IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































  1. IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



    — , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



    , , : «» , , , , «» ? , , , «», API .



    , , , , . :

    () (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



    , , .. , , . , (), — (). , , «» «» . , , . null «» , - null



    ; « », null



    — , . , , , default(IComparer), , , null



    . .



    , : (immutable). , , , , , «» (, ) .





    . — .



    public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







    , , , … . , «» (.. ) / , . Contains



    , - , .



    () (). , , . ( readonly



    ) - , .



    WithExclusiveLowerBound



    , WithInclusiveLowerBound



    , WithLowerBound



    .., . -, , . - :

    var range = Range.Of(5, 10);





    , — ́ , , . , , .





    . , ( , stepping function), . : , , .



    ?

    , — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



    , , . , — , , :

    var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






    : , IEnumerable. IEnumerator, IEnumerable: foreach



    , LINQ ..

    , …



    ?

    -, . , «» , , . , , (0, 255) Byte



    . :

    : , , — . , «». :

    * Func<Tuple<bool, T>>



    , .

    * ( out



    ) ( )

    * null



    « », , T



    .

    , «» - , () ( «»).

    , , , , , « n ». , , , .





    , , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



    , :

    public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





    : «» , , , . , : , , , , , , , .



    ( if) — :

    T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





    — , — .



    : . , — ?





    (reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

    public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





    « », ? , Compare



    (negate) … , originalComparer.Compare



    int.MinValue



    . , , int.MinValue



    . — , , , .



    . , int.MinValue



    . IComparer , , , int Compare(T x, T y) , : x



    y



    0; x



    y



    , 0; x



    , y



    , 0. .NET Framework, , x



    y



    -1 +1, , int.MinValue



    ( x



    y



    ) int.MaxValue



    ( x



    y



    ). , . 0 ,

    |int.MinValue| == int.MaxValue + 1. ,

    Int32 i = Int32.MinValue; Int32 j = -i;



    j



    int.MinValue



    , int.MaxValue



    , . , ( checked



    ), System.OverflowException



    , production- .








    , , Range



    Reverse



    :





    public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





    , , , «» ( , ), . , C# 4, , , , .



    , : , , , . , [0, 5]



    (.. 0 5 ), , 2 . { 0, 2, 4 }



    . [0, 5]



    [5, 0]



    , ( , 2), { 5, 3, 1 }



    . , , LINQ, { 4, 2, 0 }



    { 5, 3, 1 }



    .





    , « », , . , ; , , . , , , , int.MinValue



    . , , -, .







    , , , .NET.

    Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

    , , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



    , Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .
























































  2. IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



    — , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



    , , : «» , , , , «» ? , , , «», API .



    , , , , . :

    () (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



    , , .. , , . , (), — (). , , «» «» . , , . null «» , - null



    ; « », null



    — , . , , , default(IComparer), , , null



    . .



    , : (immutable). , , , , , «» (, ) .





    . — .



    public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







    , , , … . , «» (.. ) / , . Contains



    , - , .



    () (). , , . ( readonly



    ) - , .



    WithExclusiveLowerBound



    , WithInclusiveLowerBound



    , WithLowerBound



    .., . -, , . - :

    var range = Range.Of(5, 10);





    , — ́ , , . , , .





    . , ( , stepping function), . : , , .



    ?

    , — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



    , , . , — , , :

    var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






    : , IEnumerable. IEnumerator, IEnumerable: foreach



    , LINQ ..

    , …



    ?

    -, . , «» , , . , , (0, 255) Byte



    . :

    : , , — . , «». :

    * Func<Tuple<bool, T>>



    , .

    * ( out



    ) ( )

    * null



    « », , T



    .

    , «» - , () ( «»).

    , , , , , « n ». , , , .





    , , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



    , :

    public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





    : «» , , , . , : , , , , , , , .



    ( if) — :

    T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





    — , — .



    : . , — ?





    (reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

    public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





    « », ? , Compare



    (negate) … , originalComparer.Compare



    int.MinValue



    . , , int.MinValue



    . — , , , .



    . , int.MinValue



    . IComparer , , , int Compare(T x, T y) , : x



    y



    0; x



    y



    , 0; x



    , y



    , 0. .NET Framework, , x



    y



    -1 +1, , int.MinValue



    ( x



    y



    ) int.MaxValue



    ( x



    y



    ). , . 0 ,

    |int.MinValue| == int.MaxValue + 1. ,

    Int32 i = Int32.MinValue; Int32 j = -i;



    j



    int.MinValue



    , int.MaxValue



    , . , ( checked



    ), System.OverflowException



    , production- .








    , , Range



    Reverse



    :





    public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





    , , , «» ( , ), . , C# 4, , , , .



    , : , , , . , [0, 5]



    (.. 0 5 ), , 2 . { 0, 2, 4 }



    . [0, 5]



    [5, 0]



    , ( , 2), { 5, 3, 1 }



    . , , LINQ, { 4, 2, 0 }



    { 5, 3, 1 }



    .





    , « », , . , ; , , . , , , , int.MinValue



    . , , -, .







    , , , .NET.

    Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

    , , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



    , Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .
























































  3. IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



    — , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



    , , : «» , , , , «» ? , , , «», API .



    , , , , . :

    () (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



    , , .. , , . , (), — (). , , «» «» . , , . null «» , - null



    ; « », null



    — , . , , , default(IComparer), , , null



    . .



    , : (immutable). , , , , , «» (, ) .





    . — .



    public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







    , , , … . , «» (.. ) / , . Contains



    , - , .



    () (). , , . ( readonly



    ) - , .



    WithExclusiveLowerBound



    , WithInclusiveLowerBound



    , WithLowerBound



    .., . -, , . - :

    var range = Range.Of(5, 10);





    , — ́ , , . , , .





    . , ( , stepping function), . : , , .



    ?

    , — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



    , , . , — , , :

    var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






    : , IEnumerable. IEnumerator, IEnumerable: foreach



    , LINQ ..

    , …



    ?

    -, . , «» , , . , , (0, 255) Byte



    . :

    : , , — . , «». :

    * Func<Tuple<bool, T>>



    , .

    * ( out



    ) ( )

    * null



    « », , T



    .

    , «» - , () ( «»).

    , , , , , « n ». , , , .





    , , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



    , :

    public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





    : «» , , , . , : , , , , , , , .



    ( if) — :

    T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





    — , — .



    : . , — ?





    (reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

    public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





    « », ? , Compare



    (negate) … , originalComparer.Compare



    int.MinValue



    . , , int.MinValue



    . — , , , .



    . , int.MinValue



    . IComparer , , , int Compare(T x, T y) , : x



    y



    0; x



    y



    , 0; x



    , y



    , 0. .NET Framework, , x



    y



    -1 +1, , int.MinValue



    ( x



    y



    ) int.MaxValue



    ( x



    y



    ). , . 0 ,

    |int.MinValue| == int.MaxValue + 1. ,

    Int32 i = Int32.MinValue; Int32 j = -i;



    j



    int.MinValue



    , int.MaxValue



    , . , ( checked



    ), System.OverflowException



    , production- .








    , , Range



    Reverse



    :





    public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





    , , , «» ( , ), . , C# 4, , , , .



    , : , , , . , [0, 5]



    (.. 0 5 ), , 2 . { 0, 2, 4 }



    . [0, 5]



    [5, 0]



    , ( , 2), { 5, 3, 1 }



    . , , LINQ, { 4, 2, 0 }



    { 5, 3, 1 }



    .





    , « », , . , ; , , . , , , , int.MinValue



    . , , -, .







    , , , .NET.

    Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

    , , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



    , Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .
























































  4. IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



    — , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



    , , : «» , , , , «» ? , , , «», API .



    , , , , . :

    () (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



    , , .. , , . , (), — (). , , «» «» . , , . null «» , - null



    ; « », null



    — , . , , , default(IComparer), , , null



    . .



    , : (immutable). , , , , , «» (, ) .





    . — .



    public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







    , , , … . , «» (.. ) / , . Contains



    , - , .



    () (). , , . ( readonly



    ) - , .



    WithExclusiveLowerBound



    , WithInclusiveLowerBound



    , WithLowerBound



    .., . -, , . - :

    var range = Range.Of(5, 10);





    , — ́ , , . , , .





    . , ( , stepping function), . : , , .



    ?

    , — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



    , , . , — , , :

    var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






    : , IEnumerable. IEnumerator, IEnumerable: foreach



    , LINQ ..

    , …



    ?

    -, . , «» , , . , , (0, 255) Byte



    . :

    : , , — . , «». :

    * Func<Tuple<bool, T>>



    , .

    * ( out



    ) ( )

    * null



    « », , T



    .

    , «» - , () ( «»).

    , , , , , « n ». , , , .





    , , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



    , :

    public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





    : «» , , , . , : , , , , , , , .



    ( if) — :

    T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





    — , — .



    : . , — ?





    (reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

    public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





    « », ? , Compare



    (negate) … , originalComparer.Compare



    int.MinValue



    . , , int.MinValue



    . — , , , .



    . , int.MinValue



    . IComparer , , , int Compare(T x, T y) , : x



    y



    0; x



    y



    , 0; x



    , y



    , 0. .NET Framework, , x



    y



    -1 +1, , int.MinValue



    ( x



    y



    ) int.MaxValue



    ( x



    y



    ). , . 0 ,

    |int.MinValue| == int.MaxValue + 1. ,

    Int32 i = Int32.MinValue; Int32 j = -i;



    j



    int.MinValue



    , int.MaxValue



    , . , ( checked



    ), System.OverflowException



    , production- .








    , , Range



    Reverse



    :





    public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





    , , , «» ( , ), . , C# 4, , , , .



    , : , , , . , [0, 5]



    (.. 0 5 ), , 2 . { 0, 2, 4 }



    . [0, 5]



    [5, 0]



    , ( , 2), { 5, 3, 1 }



    . , , LINQ, { 4, 2, 0 }



    { 5, 3, 1 }



    .





    , « », , . , ; , , . , , , , int.MinValue



    . , , -, .







    , , , .NET.

    Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

    , , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



    , Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .
























































IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































 IComparable.     ,       ,         C# —         IComparable.  ,       ,       .  ,   ,        (reversing)            ,        . ,    . 
      



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































 IComparable.     ,       ,         C# —         IComparable.  ,       ,       .  ,   ,        (reversing)            ,        . ,    . 
      



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);

, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .
























































IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































 IComparable.     ,       ,         C# —         IComparable.  ,       ,       .  ,   ,        (reversing)            ,        . ,    . 
      



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































 IComparable.     ,       ,         C# —         IComparable.  ,       ,       .  ,   ,        (reversing)            ,        . ,    . 
      



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































 IComparable.     ,       ,         C# —         IComparable.  ,       ,       .  ,   ,        (reversing)            ,        . ,    . 
      



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);

— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .
























































IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































 IComparable.     ,       ,         C# —         IComparable.  ,       ,       .  ,   ,        (reversing)            ,        . ,    . 
      



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































 IComparable.     ,       ,         C# —         IComparable.  ,       ,       .  ,   ,        (reversing)            ,        . ,    . 
      



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .





















































IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































  • IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



    — , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



    , , : «» , , , , «» ? , , , «», API .



    , , , , . :

    () (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



    , , .. , , . , (), — (). , , «» «» . , , . null




    «» , - null



    ; « », null



    — , . , , , default(IComparer), , , null



    . .



    , : (immutable). , , , , , «» (, ) .





    . — .



    public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







    , , , … . , «» (.. ) / , . Contains



    , - , .



    () (). , , . ( readonly



    ) - , .



    WithExclusiveLowerBound



    , WithInclusiveLowerBound



    , WithLowerBound



    .., . -, , . - :

    var range = Range.Of(5, 10);





    , — ́ , , . , , .





    . , ( , stepping function), . : , , .



    ?

    , — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



    , , . , — , , :

    var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






    : , IEnumerable. IEnumerator, IEnumerable: foreach



    , LINQ ..

    , …



    ?

    -, . , «» , , . , , (0, 255) Byte



    . :

    : , , — . , «». :

    * Func<Tuple<bool, T>>



    , .

    * ( out



    ) ( )

    * null



    « », , T



    .

    , «» - , () ( «»).

    , , , , , « n ». , , , .





    , , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



    , :

    public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





    : «» , , , . , : , , , , , , , .



    ( if) — :

    T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





    — , — .



    : . , — ?





    (reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

    public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





    « », ? , Compare



    (negate) … , originalComparer.Compare



    int.MinValue



    . , , int.MinValue



    . — , , , .



    . , int.MinValue



    . IComparer , , , int Compare(T x, T y) , : x



    y



    0; x



    y



    , 0; x



    , y



    , 0. .NET Framework, , x



    y



    -1 +1, , int.MinValue



    ( x



    y



    ) int.MaxValue



    ( x



    y



    ). , . 0 ,

    |int.MinValue| == int.MaxValue + 1. ,

    Int32 i = Int32.MinValue; Int32 j = -i;



    j



    int.MinValue



    , int.MaxValue



    , . , ( checked



    ), System.OverflowException



    , production- .








    , , Range



    Reverse



    :





    public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





    , , , «» ( , ), . , C# 4, , , , .



    , : , , , . , [0, 5]



    (.. 0 5 ), , 2 . { 0, 2, 4 }



    . [0, 5]



    [5, 0]



    , ( , 2), { 5, 3, 1 }



    . , , LINQ, { 4, 2, 0 }



    { 5, 3, 1 }



    .





    , « », , . , ; , , . , , , , int.MinValue



    . , , -, .







    , , , .NET.

    Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

    , , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



    , Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































  • IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



    — , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



    , , : «» , , , , «» ? , , , «», API .



    , , , , . :

    () (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



    , , .. , , . , (), — (). , , «» «» . , , . null




    «» , - null



    ; « », null



    — , . , , , default(IComparer), , , null



    . .



    , : (immutable). , , , , , «» (, ) .





    . — .



    public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







    , , , … . , «» (.. ) / , . Contains



    , - , .



    () (). , , . ( readonly



    ) - , .



    WithExclusiveLowerBound



    , WithInclusiveLowerBound



    , WithLowerBound



    .., . -, , . - :

    var range = Range.Of(5, 10);





    , — ́ , , . , , .





    . , ( , stepping function), . : , , .



    ?

    , — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



    , , . , — , , :

    var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






    : , IEnumerable. IEnumerator, IEnumerable: foreach



    , LINQ ..

    , …



    ?

    -, . , «» , , . , , (0, 255) Byte



    . :

    : , , — . , «». :

    * Func<Tuple<bool, T>>



    , .

    * ( out



    ) ( )

    * null



    « », , T



    .

    , «» - , () ( «»).

    , , , , , « n ». , , , .





    , , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



    , :

    public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





    : «» , , , . , : , , , , , , , .



    ( if) — :

    T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





    — , — .



    : . , — ?





    (reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

    public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





    « », ? , Compare



    (negate) … , originalComparer.Compare



    int.MinValue



    . , , int.MinValue



    . — , , , .



    . , int.MinValue



    . IComparer , , , int Compare(T x, T y) , : x



    y



    0; x



    y



    , 0; x



    , y



    , 0. .NET Framework, , x



    y



    -1 +1, , int.MinValue



    ( x



    y



    ) int.MaxValue



    ( x



    y



    ). , . 0 ,

    |int.MinValue| == int.MaxValue + 1. ,

    Int32 i = Int32.MinValue; Int32 j = -i;



    j



    int.MinValue



    , int.MaxValue



    , . , ( checked



    ), System.OverflowException



    , production- .








    , , Range



    Reverse



    :





    public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





    , , , «» ( , ), . , C# 4, , , , .



    , : , , , . , [0, 5]



    (.. 0 5 ), , 2 . { 0, 2, 4 }



    . [0, 5]



    [5, 0]



    , ( , 2), { 5, 3, 1 }



    . , , LINQ, { 4, 2, 0 }



    { 5, 3, 1 }



    .





    , « », , . , ; , , . , , , , int.MinValue



    . , , -, .







    , , , .NET.

    Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

    , , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



    , Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































  • IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



    — , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



    , , : «» , , , , «» ? , , , «», API .



    , , , , . :

    () (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



    , , .. , , . , (), — (). , , «» «» . , , . null




    «» , - null



    ; « », null



    — , . , , , default(IComparer), , , null



    . .



    , : (immutable). , , , , , «» (, ) .





    . — .



    public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







    , , , … . , «» (.. ) / , . Contains



    , - , .



    () (). , , . ( readonly



    ) - , .



    WithExclusiveLowerBound



    , WithInclusiveLowerBound



    , WithLowerBound



    .., . -, , . - :

    var range = Range.Of(5, 10);





    , — ́ , , . , , .





    . , ( , stepping function), . : , , .



    ?

    , — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



    , , . , — , , :

    var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






    : , IEnumerable. IEnumerator, IEnumerable: foreach



    , LINQ ..

    , …



    ?

    -, . , «» , , . , , (0, 255) Byte



    . :

    : , , — . , «». :

    * Func<Tuple<bool, T>>



    , .

    * ( out



    ) ( )

    * null



    « », , T



    .

    , «» - , () ( «»).

    , , , , , « n ». , , , .





    , , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



    , :

    public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





    : «» , , , . , : , , , , , , , .



    ( if) — :

    T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





    — , — .



    : . , — ?





    (reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

    public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





    « », ? , Compare



    (negate) … , originalComparer.Compare



    int.MinValue



    . , , int.MinValue



    . — , , , .



    . , int.MinValue



    . IComparer , , , int Compare(T x, T y) , : x



    y



    0; x



    y



    , 0; x



    , y



    , 0. .NET Framework, , x



    y



    -1 +1, , int.MinValue



    ( x



    y



    ) int.MaxValue



    ( x



    y



    ). , . 0 ,

    |int.MinValue| == int.MaxValue + 1. ,

    Int32 i = Int32.MinValue; Int32 j = -i;



    j



    int.MinValue



    , int.MaxValue



    , . , ( checked



    ), System.OverflowException



    , production- .








    , , Range



    Reverse



    :





    public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





    , , , «» ( , ), . , C# 4, , , , .



    , : , , , . , [0, 5]



    (.. 0 5 ), , 2 . { 0, 2, 4 }



    . [0, 5]



    [5, 0]



    , ( , 2), { 5, 3, 1 }



    . , , LINQ, { 4, 2, 0 }



    { 5, 3, 1 }



    .





    , « », , . , ; , , . , , , , int.MinValue



    . , , -, .







    , , , .NET.

    Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

    , , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



    , Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































  • IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



    — , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



    , , : «» , , , , «» ? , , , «», API .



    , , , , . :

    () (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



    , , .. , , . , (), — (). , , «» «» . , , . null




    «» , - null



    ; « », null



    — , . , , , default(IComparer), , , null



    . .



    , : (immutable). , , , , , «» (, ) .





    . — .



    public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







    , , , … . , «» (.. ) / , . Contains



    , - , .



    () (). , , . ( readonly



    ) - , .



    WithExclusiveLowerBound



    , WithInclusiveLowerBound



    , WithLowerBound



    .., . -, , . - :

    var range = Range.Of(5, 10);





    , — ́ , , . , , .





    . , ( , stepping function), . : , , .



    ?

    , — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



    , , . , — , , :

    var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






    : , IEnumerable. IEnumerator, IEnumerable: foreach



    , LINQ ..

    , …



    ?

    -, . , «» , , . , , (0, 255) Byte



    . :

    : , , — . , «». :

    * Func<Tuple<bool, T>>



    , .

    * ( out



    ) ( )

    * null



    « », , T



    .

    , «» - , () ( «»).

    , , , , , « n ». , , , .





    , , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



    , :

    public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





    : «» , , , . , : , , , , , , , .



    ( if) — :

    T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





    — , — .



    : . , — ?





    (reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

    public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





    « », ? , Compare



    (negate) … , originalComparer.Compare



    int.MinValue



    . , , int.MinValue



    . — , , , .



    . , int.MinValue



    . IComparer , , , int Compare(T x, T y) , : x



    y



    0; x



    y



    , 0; x



    , y



    , 0. .NET Framework, , x



    y



    -1 +1, , int.MinValue



    ( x



    y



    ) int.MaxValue



    ( x



    y



    ). , . 0 ,

    |int.MinValue| == int.MaxValue + 1. ,

    Int32 i = Int32.MinValue; Int32 j = -i;



    j



    int.MinValue



    , int.MaxValue



    , . , ( checked



    ), System.OverflowException



    , production- .








    , , Range



    Reverse



    :





    public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





    , , , «» ( , ), . , C# 4, , , , .



    , : , , , . , [0, 5]



    (.. 0 5 ), , 2 . { 0, 2, 4 }



    . [0, 5]



    [5, 0]



    , ( , 2), { 5, 3, 1 }



    . , , LINQ, { 4, 2, 0 }



    { 5, 3, 1 }



    .





    , « », , . , ; , , . , , , , int.MinValue



    . , , -, .







    , , , .NET.

    Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

    , , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



    , Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































  • IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



    — , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



    , , : «» , , , , «» ? , , , «», API .



    , , , , . :

    () (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



    , , .. , , . , (), — (). , , «» «» . , , . null




    «» , - null



    ; « », null



    — , . , , , default(IComparer), , , null



    . .



    , : (immutable). , , , , , «» (, ) .





    . — .



    public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







    , , , … . , «» (.. ) / , . Contains



    , - , .



    () (). , , . ( readonly



    ) - , .



    WithExclusiveLowerBound



    , WithInclusiveLowerBound



    , WithLowerBound



    .., . -, , . - :

    var range = Range.Of(5, 10);





    , — ́ , , . , , .





    . , ( , stepping function), . : , , .



    ?

    , — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



    , , . , — , , :

    var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






    : , IEnumerable. IEnumerator, IEnumerable: foreach



    , LINQ ..

    , …



    ?

    -, . , «» , , . , , (0, 255) Byte



    . :

    : , , — . , «». :

    * Func<Tuple<bool, T>>



    , .

    * ( out



    ) ( )

    * null



    « », , T



    .

    , «» - , () ( «»).

    , , , , , « n ». , , , .





    , , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



    , :

    public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





    : «» , , , . , : , , , , , , , .



    ( if) — :

    T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





    — , — .



    : . , — ?





    (reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

    public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





    « », ? , Compare



    (negate) … , originalComparer.Compare



    int.MinValue



    . , , int.MinValue



    . — , , , .



    . , int.MinValue



    . IComparer , , , int Compare(T x, T y) , : x



    y



    0; x



    y



    , 0; x



    , y



    , 0. .NET Framework, , x



    y



    -1 +1, , int.MinValue



    ( x



    y



    ) int.MaxValue



    ( x



    y



    ). , . 0 ,

    |int.MinValue| == int.MaxValue + 1. ,

    Int32 i = Int32.MinValue; Int32 j = -i;



    j



    int.MinValue



    , int.MaxValue



    , . , ( checked



    ), System.OverflowException



    , production- .








    , , Range



    Reverse



    :





    public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





    , , , «» ( , ), . , C# 4, , , , .



    , : , , , . , [0, 5]



    (.. 0 5 ), , 2 . { 0, 2, 4 }



    . [0, 5]



    [5, 0]



    , ( , 2), { 5, 3, 1 }



    . , , LINQ, { 4, 2, 0 }



    { 5, 3, 1 }



    .





    , « », , . , ; , , . , , , , int.MinValue



    . , , -, .







    , , , .NET.

    Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

    , , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



    , Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































  • IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



    — , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



    , , : «» , , , , «» ? , , , «», API .



    , , , , . :

    () (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



    , , .. , , . , (), — (). , , «» «» . , , . null




    «» , - null



    ; « », null



    — , . , , , default(IComparer), , , null



    . .



    , : (immutable). , , , , , «» (, ) .





    . — .



    public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







    , , , … . , «» (.. ) / , . Contains



    , - , .



    () (). , , . ( readonly



    ) - , .



    WithExclusiveLowerBound



    , WithInclusiveLowerBound



    , WithLowerBound



    .., . -, , . - :

    var range = Range.Of(5, 10);





    , — ́ , , . , , .





    . , ( , stepping function), . : , , .



    ?

    , — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



    , , . , — , , :

    var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






    : , IEnumerable. IEnumerator, IEnumerable: foreach



    , LINQ ..

    , …



    ?

    -, . , «» , , . , , (0, 255) Byte



    . :

    : , , — . , «». :

    * Func<Tuple<bool, T>>



    , .

    * ( out



    ) ( )

    * null



    « », , T



    .

    , «» - , () ( «»).

    , , , , , « n ». , , , .





    , , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



    , :

    public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





    : «» , , , . , : , , , , , , , .



    ( if) — :

    T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





    — , — .



    : . , — ?





    (reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

    public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





    « », ? , Compare



    (negate) … , originalComparer.Compare



    int.MinValue



    . , , int.MinValue



    . — , , , .



    . , int.MinValue



    . IComparer , , , int Compare(T x, T y) , : x



    y



    0; x



    y



    , 0; x



    , y



    , 0. .NET Framework, , x



    y



    -1 +1, , int.MinValue



    ( x



    y



    ) int.MaxValue



    ( x



    y



    ). , . 0 ,

    |int.MinValue| == int.MaxValue + 1. ,

    Int32 i = Int32.MinValue; Int32 j = -i;



    j



    int.MinValue



    , int.MaxValue



    , . , ( checked



    ), System.OverflowException



    , production- .








    , , Range



    Reverse



    :





    public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





    , , , «» ( , ), . , C# 4, , , , .



    , : , , , . , [0, 5]



    (.. 0 5 ), , 2 . { 0, 2, 4 }



    . [0, 5]



    [5, 0]



    , ( , 2), { 5, 3, 1 }



    . , , LINQ, { 4, 2, 0 }



    { 5, 3, 1 }



    .





    , « », , . , ; , , . , , , , int.MinValue



    . , , -, .







    , , , .NET.

    Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

    , , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



    , Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































  • IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



    — , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



    , , : «» , , , , «» ? , , , «», API .



    , , , , . :

    () (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



    , , .. , , . , (), — (). , , «» «» . , , . null




    «» , - null



    ; « », null



    — , . , , , default(IComparer), , , null



    . .



    , : (immutable). , , , , , «» (, ) .





    . — .



    public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







    , , , … . , «» (.. ) / , . Contains



    , - , .



    () (). , , . ( readonly



    ) - , .



    WithExclusiveLowerBound



    , WithInclusiveLowerBound



    , WithLowerBound



    .., . -, , . - :

    var range = Range.Of(5, 10);





    , — ́ , , . , , .





    . , ( , stepping function), . : , , .



    ?

    , — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



    , , . , — , , :

    var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






    : , IEnumerable. IEnumerator, IEnumerable: foreach



    , LINQ ..

    , …



    ?

    -, . , «» , , . , , (0, 255) Byte



    . :

    : , , — . , «». :

    * Func<Tuple<bool, T>>



    , .

    * ( out



    ) ( )

    * null



    « », , T



    .

    , «» - , () ( «»).

    , , , , , « n ». , , , .





    , , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



    , :

    public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





    : «» , , , . , : , , , , , , , .



    ( if) — :

    T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





    — , — .



    : . , — ?





    (reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

    public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





    « », ? , Compare



    (negate) … , originalComparer.Compare



    int.MinValue



    . , , int.MinValue



    . — , , , .



    . , int.MinValue



    . IComparer , , , int Compare(T x, T y) , : x



    y



    0; x



    y



    , 0; x



    , y



    , 0. .NET Framework, , x



    y



    -1 +1, , int.MinValue



    ( x



    y



    ) int.MaxValue



    ( x



    y



    ). , . 0 ,

    |int.MinValue| == int.MaxValue + 1. ,

    Int32 i = Int32.MinValue; Int32 j = -i;



    j



    int.MinValue



    , int.MaxValue



    , . , ( checked



    ), System.OverflowException



    , production- .








    , , Range



    Reverse



    :





    public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





    , , , «» ( , ), . , C# 4, , , , .



    , : , , , . , [0, 5]



    (.. 0 5 ), , 2 . { 0, 2, 4 }



    . [0, 5]



    [5, 0]



    , ( , 2), { 5, 3, 1 }



    . , , LINQ, { 4, 2, 0 }



    { 5, 3, 1 }



    .





    , « », , . , ; , , . , , , , int.MinValue



    . , , -, .







    , , , .NET.

    Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

    , , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



    , Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .




















































IComparable. , , C# — IComparable. , , . , , (reversing) , . , .



— , «-», , (). : IComparer, Comparison? , IComparer, , , . , Comparer.Default . , , Comparison, , - ( MiscUtil).



, , : «» , , , , «» ? , , , «», API .



, , , , . :

() (inclusive) (exclusive), , . , , ? , , .. ? , ()? , ?



, , .. , , . , (), — (). , , «» «» . , , . null




«» , - null



; « », null



— , . , , , default(IComparer), , , null



. .



, : (immutable). , , , , , «» (, ) .





. — .



public sealed class Range<T> { public T LowerBound { get; private set; } public T UpperBound { get; private set; } public bool InclusiveLowerBound { get; private set; } public bool InclusiveUpperBound { get; private set; } public IComparer<T> Comparer { get; private set; } public Range(T lowerBound, T upperBound, bool inclusiveLowerBound = true, bool inclusiveUpperBound = false, IComparer<T> comparer = null) { LowerBound = lowerBound; UpperBound = upperBound; InclusiveLowerBound = inclusiveLowerBound; InclusiveUpperBound = inclusiveUpperBound; Comparer = comparer ?? Comparer<T>.Default; if (Comparer.Compare(LowerBound, UpperBound) > 0) { throw new ArgumentException("Invalid bounds"); } } public bool Contains(T item) { int lowerCompare = Comparer.Compare(LowerBound, item); if (lowerCompare > (InclusiveLowerBound ? 0 : -1)) { return false; } int upperCompare = Comparer.Compare(item, UpperBound); if (upperCompare > (InclusiveUpperBound ? 0 : -1)) { return false; } return true; } }







, , , … . , «» (.. ) / , . Contains



, - , .



() (). , , . ( readonly



) - , .



WithExclusiveLowerBound



, WithInclusiveLowerBound



, WithLowerBound



.., . -, , . - :

var range = Range.Of(5, 10);





, — ́ , , . , , .





. , ( , stepping function), . : , , .



?

, — . , — . , (0, 50), , — 5. 1 ( ) 5 ( 0 )? , , , () . , - IComparer, . «» (41, 37), 23, 12 44, 38. .



, , . , — , , :

var range = new Range<int>(0, 50, false, false); var simpleIterable = range.StepBy(x => x + 5); var equivalentIterable = range.WithInclusiveLowerBound() .StepBy(x => x + 5) .Skip(1);






: , IEnumerable. IEnumerator, IEnumerable: foreach



, LINQ ..

, …



?

-, . , «» , , . , , (0, 255) Byte



. :

: , , — . , «». :

* Func<Tuple<bool, T>>



, .

* ( out



) ( )

* null



« », , T



.

, «» - , () ( «»).

, , , , , « n ». , , , .





, , , . MiscUtil, , — . , . MiscUtil ( Marc Gravell ), , (+), , .



, :

public IEnumerable<T> StepBy(Func<T, T> step) { T current = LowerBound; // , if (!InclusiveLowerBound) { current = step(current); } while (Contains(current)) { yield return current; T next = step(current); // Handle a stepping function which wraps // round from a value near the end to one // near the start; or a stepping function // which does nothing. if (Comparer.Compare(next, current) <= 0) { yield break; } current = next; } }





: «» , , , . , : , , , , , , , .



( if) — :

T current = InclusiveLowerBound ? LowerBound : step(LowerBound);





— , — .



: . , — ?





(reversing) , . , «» / «» , . , (reversing comparer) — , , . , «» :

public sealed class ReverseComparer<T> : IComparer<T> { private readonly IComparer<T> originalComparer; public ReverseComparer(IComparer<T> originalComparer) { this.originalComparer = originalComparer; } public int Compare(T x, T y) { return originalComparer.Compare(y, x); } }





« », ? , Compare



(negate) … , originalComparer.Compare



int.MinValue



. , , int.MinValue



. — , , , .



. , int.MinValue



. IComparer , , , int Compare(T x, T y) , : x



y



0; x



y



, 0; x



, y



, 0. .NET Framework, , x



y



-1 +1, , int.MinValue



( x



y



) int.MaxValue



( x



y



). , . 0 ,

|int.MinValue| == int.MaxValue + 1. ,

Int32 i = Int32.MinValue; Int32 j = -i;



j



int.MinValue



, int.MaxValue



, . , ( checked



), System.OverflowException



, production- .








, , Range



Reverse



:





public Range<T> Reverse() { return new Range<T>( lowerBound: UpperBound, upperBound: LowerBound, inclusiveLowerBound: InclusiveUpperBound, inclusiveUpperBound: InclusiveLowerBound, comparer:new ReverseComparer<T>(Comparer)); }





, , , «» ( , ), . , C# 4, , , , .



, : , , , . , [0, 5]



(.. 0 5 ), , 2 . { 0, 2, 4 }



. [0, 5]



[5, 0]



, ( , 2), { 5, 3, 1 }



. , , LINQ, { 4, 2, 0 }



{ 5, 3, 1 }



.





, « », , . , ; , , . , , , , int.MinValue



. , , -, .







, , , .NET.

Dmitri Nstruk. Ranges in C# Qwertie. D-style ranges in C# (.NET) Sean Hederman. Building a Generic Range class Scott McMaster. RangeSet: A Low-Memory Set Data Structure for Integers Jay Bazuzi. Comparing ranges Sergio Pereira. Language Envy - C# needs Ranges Andy Clymer. Ruby Ranges in .NET

, , MiscUtil. , , . -, , , . Range MiscUtil , , RangeIterator. , MiscUtil, , " ".



, Time Period Library Jani Giannoudis. 2011 CodeProject, ( — 1 2013), - ( - ), Silverlight Windows Phone. overkill hDrummer .























































All Articles