Я реализовал простенький IEnumerable<CSVLine>
для чтения CSV
файлов.
Правильно ли реализованы IEnumerator<>
ы?
CSVStream:
public class CSVStream : IEnumerable<CSVLine>
{
private readonly char[] _separators;
public IReadOnlyCollection<char> Separators
{
get { return _separators; }
}
public CSVStream(string filePath, Encoding encoding = null, params char[] separators)
{
Encoding = encoding ?? Encoding.UTF8;
_separators = separators ?? new []{','};
FilePath = filePath;
}
public Encoding Encoding { get; }
public string FilePath { get; }
public IEnumerator<CSVLine> GetEnumerator()
{
return new CSVStreamEnumerator(FilePath, _separators, Encoding);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
CSVStreamEnumerator:
public class CSVStreamEnumerator : IEnumerator<CSVLine>
{
private readonly StreamReader _fileStream;
private CSVLine _current;
private readonly char[] _separators;
public CSVStreamEnumerator(string filePath, char[] separators, Encoding encoding = null)
{
Encoding = encoding ?? Encoding.UTF8;
_separators = separators;
_fileStream =
new StreamReader(filePath, Encoding);
}
public Encoding Encoding { get; }
public bool IsDisposed { get; protected set; }
public bool MoveNext()
{
string currentString = _fileStream.ReadLine();
return !((currentString is null
? _current = null
: _current = new CSVLine(currentString, _separators)) is null);
}
public void Reset()
{
_fileStream.DiscardBufferedData();
_fileStream.BaseStream.Seek(0, SeekOrigin.Begin);
_current = null;
}
public CSVLine Current
{
get
{
if (_fileStream == null || _current == null)
{
throw new InvalidOperationException();
}
return _current;
}
}
object IEnumerator.Current
{
get { return Current; }
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (IsDisposed)
{
return;
}
_current = null;
_fileStream?.Close();
_fileStream?.Dispose();
IsDisposed = true;
}
~CSVStreamEnumerator()
{
Dispose(false);
}
}
CSVLine:
public class CSVLine : IEnumerable<string>
{
private readonly string[] _values;
public CSVLine(string value, char[] separators)
{
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
_values = value.Split
(
separators ?? new[] {','},
StringSplitOptions.None
).Select(s => s.Replace("\"\"", "\x0000").Trim('\"').Replace("\x0000", "\"")).ToArray();
}
public CSVLine(string[] values)
{
_values = values;
}
public int Count
{
get { return _values.Length; }
}
public IEnumerator<string> GetEnumerator()
{
return new CSVLineEnumerator(_values);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public static implicit operator CSVLine(string val)
{
return new CSVLine(value: val, new []{','});
}
public static implicit operator CSVLine(string[] values)
{
return new CSVLine(values);
}
}
CSVLineEnumerator
public class CSVLineEnumerator : IEnumerator<string>
{
private int _currentIndex;
private string[] _values;
public CSVLineEnumerator(string[] values)
{
_values = values;
_currentIndex = -1;
}
public bool IsDisposed { get; protected set; }
public bool MoveNext()
{
if (_currentIndex == _values.Length - 1)
{
return false;
}
_currentIndex++;
return true;
}
public void Reset()
{
_currentIndex = 0;
}
public string Current
{
get { return _values[_currentIndex]; }
}
object IEnumerator.Current
{
get { return Current; }
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (IsDisposed)
{
return;
}
if (disposing)
{
_values = null;
}
IsDisposed = true;
}
~CSVLineEnumerator()
{
Dispose(false);
}
}
Чтение через foreach
:
[TestMethod]
public void EnumeratorTest()
{
CSVStream stream = new CSVStream("D:\\test.csv", Encoding.UTF8, ';');
foreach (CSVLine csvLine in stream)
{
foreach (string value in csvLine)
{
Console.Out.Write("\'{0}\' ", value);
}
Console.Out.WriteLine(Environment.NewLine);
}
}
За основу взял тестовый текст из википедии:
1965;Пиксель;E240 – формальдегид (опасный консервант)!;"красный, зелёный, битый";"3000,00"
1965;Мышка;"А правильней использовать ""Ёлочки""";;"4900,00"
"Н/д";Кнопка;Сочетания клавиш;"MUST USE! Ctrl, Alt, Shift";"4799,00"
На выходе получил такйо результат:
'1965' 'Пиксель' 'E240 – формальдегид (опасный консервант)!' 'красный, зелёный, битый' '3000,00'
'1965' 'Мышка' 'А правильней использовать "Ёлочки"' '' '4900,00'
'Н/д' 'Кнопка' 'Сочетания клавиш' 'MUST USE! Ctrl, Alt, Shift' '4799,00'
P.S. Знаю что вот этот кусок кода:
_values = value.Split
(
separators ?? new[] {','},
StringSplitOptions.RemoveEmptyEntries
).Select(s => s.Replace("\"\"", "\x0000").Trim('\"').Replace("\x0000", "\"")).ToArray();
Выглядит как "бред сивой кобылы", но другого способа безболезненого удаления двойных кавычек и удаления ковычек из теста я не нашел =).
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Объясните как передать active из листа с типом GameObject в лист типа bool ?
Доброго времени сутокВозникла проблема с регистрацией типов в IContainerRegistry с фабрикой