C# - Python range 함수 구현 (2) INumber<T>를 이용한 개선
다음의 기능이 나왔으니,
.NET 6 Preview 7에 추가된 숫자 형식에 대한 제네릭 연산 지원
; https://www.sysnet.pe.kr/2/0/12785
이제 Python의 Range 함수를,
C# - Python range 함수 구현
; https://www.sysnet.pe.kr/2/0/11908
더 매끄럽게 구현할 수 있습니다. ^^ 이렇게!
public static IEnumerable<T> Range<T>(T start, T stop, T step = default) where T: INumber<T>
{
if (step == default)
{
step = T.One;
}
if (start < stop && step > T.Zero)
{
for (var i = start; i < stop; i += step)
{
yield return i;
}
}
else if (start > stop && step < T.Zero)
{
for (var i = start; i > stop; i += step)
{
yield return i;
}
}
}
dynamic을 쓸 필요도 없고 unmanaged 제약으로 unsafe를 쓸 필요도 없어졌습니다. 당연히 출력 결과도 기존의 코드와 완전히 동일합니다. ^^
static void Main(string[] args)
{
{
var expected = Extension.RangePython<int>(1, 10, 1); // 기존 방식
var results = Extension.Range(1, 10); // 새로운 방식
foreach (var item in results.Zip(expected, (first, second) => Tuple.Create(first, second)))
{
Console.WriteLine($"{item.Item1} == {item.Item2}: {item.Item1 == item.Item2}");
}
}
Console.WriteLine();
{
var expected = Extension.RangePython<double>(0.1, .13, 0.001); // 기존 방식
var results = Extension.Range(0.1, .13, 0.001); // 새로운 방식
foreach (var item in results.Zip(expected, (first, second) => Tuple.Create(first, second)))
{
Console.WriteLine($"{item.Item1} == {item.Item2}: {item.Item1 == item.Item2}");
}
}
}
/* 출력 결과
1 == 1: True
2 == 2: True
3 == 3: True
4 == 4: True
5 == 5: True
6 == 6: True
7 == 7: True
8 == 8: True
9 == 9: True
0.1 == 0.1: True
0.101 == 0.101: True
0.10200000000000001 == 0.10200000000000001: True
0.10300000000000001 == 0.10300000000000001: True
0.10400000000000001 == 0.10400000000000001: True
0.10500000000000001 == 0.10500000000000001: True
0.10600000000000001 == 0.10600000000000001: True
0.10700000000000001 == 0.10700000000000001: True
0.10800000000000001 == 0.10800000000000001: True
0.10900000000000001 == 0.10900000000000001: True
0.11000000000000001 == 0.11000000000000001: True
0.11100000000000002 == 0.11100000000000002: True
0.11200000000000002 == 0.11200000000000002: True
0.11300000000000002 == 0.11300000000000002: True
0.11400000000000002 == 0.11400000000000002: True
0.11500000000000002 == 0.11500000000000002: True
0.11600000000000002 == 0.11600000000000002: True
0.11700000000000002 == 0.11700000000000002: True
0.11800000000000002 == 0.11800000000000002: True
0.11900000000000002 == 0.11900000000000002: True
0.12000000000000002 == 0.12000000000000002: True
0.12100000000000002 == 0.12100000000000002: True
0.12200000000000003 == 0.12200000000000003: True
0.12300000000000003 == 0.12300000000000003: True
0.12400000000000003 == 0.12400000000000003: True
0.12500000000000003 == 0.12500000000000003: True
0.12600000000000003 == 0.12600000000000003: True
0.12700000000000003 == 0.12700000000000003: True
0.12800000000000003 == 0.12800000000000003: True
0.12900000000000003 == 0.12900000000000003: True
(
첨부 파일은 이 글의 예제 코드를 포함합니다.)
그런데, 한 가지 아쉬운 것이 있군요. ^^
public static IEnumerable<T> Range<T>(T start, T stop, T step = default) where T: INumber<T>
{
if (step == default)
{
step = T.One;
}
// ...[생략]...
}
위의 코드에서 T step의 기본값을 default로 주었는데, 원래는 다음과 같이 설정할 수 있었으면 더 좋았을 것입니다.
public static IEnumerable<T> Range<T>(T start, T stop, T step = T.One) where T: INumber<T>
하지만, 메서드 선언에서의 문맥 단계에서는 T에 대한 풀이를 아직 제공하지 않는 것인지(혹은 못하는 것인지) 현재는 다음과 같은 컴파일 오류가 발생합니다.
error CS0103: The name 'T' does not exist in the current context
이것만 더해진다면 완벽하지 않을까... 싶군요. ^^
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]