How to generalize using C# generics?

I'm trying to make a structure that can parse various file formats into entity type objects for storage in the database.

I want to make the code as easy as possible to read and extend with further file formats and entity types independently of each other.

In general I have a fileparser, which consumes a file and returns a DTO model. This DTO model is then consumed by a converter, which returns a database entity object. Both the parser, the converter and the DTO model extends abstract classes to avoid code duplication. The process is conducted by a class called Service.

Here's the essence of the code:

class Service
{
    public void Run()
    {
        var model = new DerivedModel<DerivedRow>();
        var parser = new DerivedParser<DerivedModel<DerivedRow>>(model);
    }
}

class DerivedModel<TRow> : AbstractModel<DerivedRow>
    where TRow : DerivedRow
{
    public override DerivedRow NewRow()
    {
        return new DerivedRow();
    }
}

abstract class AbstractModel<TRow>
{
    public abstract TRow NewRow();
}

class DerivedRow : AbstractRow
{
}

abstract class AbstractRow
{
}

class DerivedParser<TModel> : AbstractParser<TModel>
    where TModel : AbstractModel<AbstractRow>
{
    public DerivedParser(TModel model)
    {
        Model = model;
    }

    public override TModel Parse()
    {
        var row = Model.NewRow();
        return Model;
    }
}

abstract class AbstractParser<TModel>
{
    public TModel Model { get; protected set; }

    public abstract TModel Parse();
}

The typechecker complains on THIS line of code in the Service class:

var parser = new DerivedParser<DerivedModel<DerivedRow>>(model);

The error is:

Error CS0311 The type 'Sandbox.GenericTest.DerivedModel<Sandbox.GenericTest.DerivedRow>' cannot be used as type parameter 'TModel' in the generic type or method 'DerivedParser<TModel>'. There is no implicit reference conversion from 'Sandbox.GenericTest.DerivedModel<Sandbox.GenericTest.DerivedRow>' to 'Sandbox.GenericTest.AbstractModel<Sandbox.GenericTest.AbstractRow>'.

I have tried using some interfaces in combination with the abstract classes, but this only complicated things.

Any suggestions? Is what I'm trying to do even possible in C# this way?

Upvotes: 0

Views: 196

Answers (1)

Rudresha Parameshappa
Rudresha Parameshappa

Reputation: 3926

try to pass TModel and the error goes away. You need to mention the type of Model to AbstractParser. Once you pass that error goes away. Here is the code

class Service
{
    public void Run()
    {
        var model = new DerivedModel<DerivedRow>();
        var parser = new DerivedParser<DerivedModel<DerivedRow>, DerivedRow>(model);
    }
}

class DerivedModel<TRow> : AbstractModel<DerivedRow>
    where TRow : DerivedRow
{
    public override DerivedRow NewRow()
    {
        return new DerivedRow();
    }
}

abstract class AbstractModel<TRow> where TRow : AbstractRow
{
    public abstract TRow NewRow();
}

class DerivedRow : AbstractRow
{
}

abstract class AbstractRow
{
}



class DerivedParser<TModel, TRow> : AbstractParser<TModel, TRow>
        where TModel : AbstractModel<TRow> where TRow : AbstractRow
{
    public DerivedParser(TModel model)
    {
        Model = model;
    }

    public override TModel Parse()
    {
        var row = Model.NewRow();
        return Model;
    }
}

abstract class AbstractParser<TModel, TRow> where TRow : AbstractRow
{
    public TModel Model { get; protected set; }

    public abstract TModel Parse();
}

Upvotes: 1

Related Questions