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&lt;NameFile, FullName&gt;
{
    protected override IEnumerable&lt;FullName&gt; Read(RowReader reader)
    {
        using(reader)
            while (reader.Read())
                yield return new FullName
                {
                    First = reader.Get&lt;string&gt;("First"),
                    Last = reader.Get&lt;string&gt;("Last")
                };
    }
}


Where FullName is:

public class FullName
{
    public string First { get; set; }
    public string Last { get; set; }
}


Using library class RowFile&lt;TFile, TRow&gt;:

public abstract class RowFile&lt;TFile, TRow&gt; : Enumerable&lt;TRow&gt;
    where TFile : RowFile&lt;TFile, TRow&gt;, new()
{
    public static readonly TFile Empty = new TFile();

    public static TFile Parse(string text) =&gt;
        Load(new StringReader(text));

    public static TFile Load(string filePath) =&gt;
        Load(File.OpenText(filePath));

    public static TFile Load(Stream stream) =&gt;
        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&lt;TRow&gt; GetEnumerator() =&gt;
        Rows.GetEnumerator();

    protected abstract IEnumerable&lt;TRow&gt; Read(RowReader read);
    IEnumerable&lt;TRow&gt; Rows { get; set; } = new TRow[0];
}


Where:

public abstract class RowReader : IDisposable
{
    public static Func&lt;TextReader, RowReader&gt; Create { get; protected set; }
    public abstract void Dispose();
    public abstract bool Read();
    public abstract T Get&lt;T&gt;(string name);
}


And:

public abstract class Enumerable&lt;T&gt; : IEnumerable&lt;T&gt;
{
    public abstract IEnumerator&lt;T&gt; GetEnumerator();
    IEnumerator IEnumerable.GetEnumerator() =&gt;
        GetEnumerator();
}


3rd party CSV reader dependency is incapsulated in MyProject.CsvHelper project:

public class CsvRowReader : RowReader
{
    public static void Use() =&gt;
        Create = reader =&gt; new CsvRowReader(reader);

    CsvRowReader(TextReader reader)
    {
        Reader = new CsvReader(reader);
        Reader.Read();
        Reader.ReadHeader();
    }

    CsvReader Reader { get; }

    public override void Dispose() =&gt;
        Reader.Dispose();

    public override bool Read() =&gt;
        Reader.Read();

    public override T Get&lt;T&gt;(string name) =&gt;
        Reader.GetField&lt;T&gt;(name);
}


I don’t like all those mutability things, but do not see a better solution at the moment...
public static TFile Load(TextReader reader)
{
    var file = new TFile();
    file.Rows = file.Read(RowReader.Create(reader));
    return file;
}



In order to get rid of the mutable property file.Rows I suggest taking a look at Autofac's factory delegate for creating TFile immutably and injecting this delegate as a dependency. 

Alternatively you could register them via named and keyed services and pick the right factory by TKey with Type as key. I use this techniques quite often.

I guess other dependency injection frameworks could do similar magic.