Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Generic Return Type with Different Generic Parameter

I'm working with a pipeline of different CSV files so wanting to write a generic reader and writer, just passing the necessary types. RegisterClassMap() normally takes a Mapper you defined. The first example is working code not using generics.

    public static IEnumerable<CacheEntryRequest> ReadCacheRequestFile(string filename)
    {
        List<CacheEntryRequest> requests;
        using (var sr = new StreamReader(filename))
        {
            var csv = new CsvReader(sr);
            csv.Configuration.RegisterClassMap<CacheEntryRequestMapper>();
            requests = csv.GetRecords<CacheEntryRequest>().ToList();
        }

        return requests;
    }

What follows is my failing attempt to write a generic method with a generic parameter for the Mapper type:

    public static IEnumerable<TR> Read<TR, TMap>(string filename)
    {
        List<TR> records;
        using (var sr = new StreamReader(filename))
        {
            var csv = new CsvReader(sr);
            csv.Configuration.RegisterClassMap<TMap>();
            records = csv.GetRecords<TR>().ToList();
        }
        return records;
    }

After which RegisterClassMap complains:

The type 'TMap' cannot be used as a type parameter 'TMap' in the generic type or method 'CsvConfiguration.RegisterClassMap()'. There is no boxing or unboxing conversion or type parameter conversion from 'TMap' to 'CsvHelper.Configuration.CsvClassMap'.

Desired usage would be:

        var records = CsvFile.Read<CacheEntryRequest, CacheEntryRequestMapper>(filename);
like image 221
disassemble-number-5 Avatar asked Feb 28 '26 22:02

disassemble-number-5


2 Answers

In order to be able to use TMap, TMap needs to be compatible with the input type of the RegisterClassMap<T> method.

You can do that using generic constraint. See https://msdn.microsoft.com/en-us/library/d5x73970.aspx.

In your case you will need to change the method signature to public static IEnumerable<TR> Read<TR, TMap>(string filename) where TMap : CsvClassMap or something like that.

Probably the class CacheEntryRequest has a base class. That will be your generic constraint.

Now. assuming you have a mapping class like

public class CustomCacheEntryRequestMapper :  CsvClassMap
{
    ...
}

You can then call your method like:

var records = CsvFile.Read<CacheEntryRequest, CustomCacheEntryRequestMapper >(filename); 
like image 171
Peter Bons Avatar answered Mar 02 '26 14:03

Peter Bons


To add to the answer that @PeterBons gave, multiple constraints, are added like this

public static IEnumerable<TR> Read<TR, TMap>(string filename) 
    where TMap : OneClass
    where TR : AnotherClass
like image 26
Luis Lavieri Avatar answered Mar 02 '26 12:03

Luis Lavieri