Python의 zip과 with 문 context를 C#과 비교하면.
python 2에서는 zip과 itertools.izip이 있고, 3에서는 izip이 zip으로 제공된다고 하는데요. tuple을 언어에 내장하다 보니 사용법 자체는 매우 간단합니다.
s = [1, 2, 3];
t = ["One", "Two", "Three"];
for x, y in zip(s, t):
print str(x) + ": " + y
C#이라면 .NET 4.0부터 확장 메소드로 Enumerable.Zip이 있습니다.
Enumerable.Zip<TFirst, TSecond, TResult> Method
; https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.zip
가끔 C# 질문글에 보면 foreach로 2개의 목록을 어떻게 열람할 수 있느냐는 것이 나오는데요. 즉 다음과 같은 식의 기능을 원하는 것입니다.
int[] numbers = { 1, 2, 3 };
string[] words = { "one", "two", "three" };
foreach (int n in numbers)
foreach (string txt in words)
{
Console.WriteLine(n + ":" + txt);
}
물론, 위의 코드는 의도한 대로 동작하지 않습니다. 이런 경우 대부분의 답변은 그냥 for 문으로 돌려야 한다는 것인데, 아쉽게도 그건 배열에 한해서 적용될 뿐 IEnumerable 인터페이스를 구현한 경우에는 쓸 수가 없습니다.
바로 이런 경우에 파이썬처럼 다음과 같이 Tuple과 함께 Zip을 사용하면 해결할 수 있습니다.
int[] numbers = { 1, 2, 3 };
string[] words = { "one", "two", "three" };
var numbersAndWords = numbers.Zip(words, (first, second) => Tuple.Create(first, second));
foreach (var item in numbersAndWords)
Console.WriteLine(item.Item1 + ", " + item.Item2);
참고로, numbers와 words의 배열 수가 다르면 작은 크기에 맞춰서 numbersAndWords의 수가 정해집니다.
그다음, 파이썬에는 __enter__, __exit__ 기능을 활용한 with 문 기능이 있습니다. 제가 보고 있는 책(
Programming Insight 파이썬 완벽 가이드)에서는 이 기능의 예제로 "값 변경에 대한 트랜잭션 구현"을 제시하고 있는데 대략 다음과 같습니다.
class ValueTransaction(object):
def __init__(self, firstValue):
self.orgValue = firstValue
def __enter__(self):
self.copyValue = self.orgValue
def __exit__(self, exctype, value, tb):
if exctype is not None:
self.orgValue = self.copyValue
def setValue(self, newValue):
self.orgValue = newValue
a = ValueTransaction(6)
try:
with a:
a.setValue(5)
# raise RuntimeError("exception occurred!") // 예외를 발생시키면 값은 6
except RuntimeError:
pass
print a.orgValue
이 기능을 C#에서 구현할 수 있을까요? 넵. using과 IDisposable 인터페이스를 이용하면 다음과 같이 동일하게 구현할 수 있습니다.
public class ValueTransaction : IDisposable
{
int? _orgValue;
int? _copyValue;
public int? Value { get { return _orgValue.Value; } }
public ValueTransaction(int initValue)
{
_orgValue = initValue;
}
public void SetValue(int newValue)
{
_copyValue = newValue;
}
public void Dispose()
{
int exceptionCode = Marshal.GetExceptionCode();
if (exceptionCode == 0)
{
if (_copyValue.HasValue == true)
{
_orgValue = _copyValue;
}
}
}
}
ValueTransaction a = new ValueTransaction(6);
try
{
using (a)
{
a.SetValue(5);
// throw new ApplicationException(); // 예외가 발생하면 6
}
}
catch (Exception) { }
Console.WriteLine(a.Value);
어쨌든, 확실히 C# 측의 코드가 길어지는 면이 있습니다. ^^ (Java는 C#의 using 문과 같은 기능이 7부터 제공된다고 합니다.)
첨부된 파일은 위의 코드를 담고 있는 솔루션 프로젝트입니다.
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]