public class NameFile : RowFile<NameFile, FullName>
{
protected override IEnumerable<FullName> Read(RowReader reader)
{
using(reader)
while (reader.Read())
yield return new FullName
{
First = reader.Get<string>("First"),
Last = reader.Get<string>("Last")
};
}
}
public class NameFile : RowFile<NameFile, FullName>
{
protected override IEnumerable<FullName> Read(RowReader reader)
{
while (reader.Read())
yield return new FullName
{
First = reader.Get<string>("First"),
Last = reader.Get<string>("Last")
};
}
}
public class NameFile : RowFile<NameFile, FullName>
{
protected override IEnumerable<FullName> Read(RowReader reader)
{
using(reader)
while (reader.Read())
yield return new FullName
{
First = reader.Get<string>("First"),
Last = reader.Get<string>("Last")
};
}
}
Using library class FowFile<TFileRowFile<TFile, TRow>
:
Using library class FowFile<TFile, TRow>
:
Using library class RowFile<TFile, TRow>
:
Inverting 3rd party dependency
Looking for a way to efficiently use 3rd party CSV reader without making a dependency on it. I would also prefer to make my class be available everywhere (not just in IoC container injectable Services), so I decided to go with a questionable decision – configure through the static property. Can you see a way to reduce amount of library code or make configuration more obvious without losing library handiness?
Repository at GitHub.
Project dependencies are:
And solution looks like this:
MyProject.Demo registers CSV library parser dependency and parses the CSV file:
class Program
{
static void Main(string[] args)
{
CsvRowReader.Use();
var text = "First,Last\nJohn,Doe\n";
var file = NameFile.Parse(text);
foreach (var name in file)
WriteLine($"{name.First} {name.Last}");
}
}
Business logic assembly MyProject defines NameFile
as:
public class NameFile : RowFile<NameFile, FullName>
{
protected override IEnumerable<FullName> Read(RowReader reader)
{
while (reader.Read())
yield return new FullName
{
First = reader.Get<string>("First"),
Last = reader.Get<string>("Last")
};
}
}
Where FullName
is:
public class FullName
{
public string First { get; set; }
public string Last { get; set; }
}
Using library class FowFile<TFile, TRow>
:
public abstract class RowFile<TFile, TRow> : Enumerable<TRow>
where TFile : RowFile<TFile, TRow>, new()
{
public static readonly TFile Empty = new TFile();
public static TFile Parse(string text) =>
Load(new StringReader(text));
public static TFile Load(string filePath) =>
Load(File.OpenText(filePath));
public static TFile Load(Stream stream) =>
Load(new StreamReader(stream));
public static TFile Load(TextReader reader)
{
var file = new TFile();
file.Rows = file.Read(RowReader.Create(reader));
return file;
}
public sealed override IEnumerator<TRow> GetEnumerator() =>
Rows.GetEnumerator();
protected abstract IEnumerable<TRow> Read(RowReader read);
IEnumerable<TRow> Rows { get; set; } = new TRow[0];
}
Where:
public abstract class RowReader : IDisposable
{
public static Func<TextReader, RowReader> Create { get; protected set; }
public abstract void Dispose();
public abstract bool Read();
public abstract T Get<T>(string name);
}
And:
public abstract class Enumerable<T> : IEnumerable<T>
{
public abstract IEnumerator<T> GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() =>
GetEnumerator();
}
3rd party CSV reader dependency is incapsulated in MyProject.CsvHelper project:
public class CsvRowReader : RowReader
{
public static void Use() =>
Create = reader => new CsvRowReader(reader);
CsvRowReader(TextReader reader)
{
Reader = new CsvReader(reader);
Reader.Read();
Reader.ReadHeader();
}
CsvReader Reader { get; }
public override void Dispose() =>
Reader.Dispose();
public override bool Read() =>
Reader.Read();
public override T Get<T>(string name) =>
Reader.GetField<T>(name);
}
I don’t like all those mutability things, but do not see a better solution at the moment...