John Bustos
John Bustos

Reputation: 19574

C# Generics - Know which derived class to use in an Abstract Method

I am working on a C# project to parse files of different kinds. In order to do this, I have created the following kind of class structure:

interface FileType {}
    class FileType1 : FileType {}
    class FileType2 : FileType {}

abstract class FileProcessor {}
    class Processor_FileType1 : FileProcessor {} // Will use FileType1 - type of storage class
    class Processor_FileType2 : FileProcessor {} // Will use FileType2 - type of storage class

So, since each FileProcessor uses a different kind of FileType, I was hoping to write some kind of method in my Base FileProcessor class to be able to get the values from the file looking something along the lines of:

abstract class FileProcessor 
{
    protected List<T> getValuesFromFile<T>() where T:FileType
    {
        try
        {
            otherClass.doProcess<T>();
        }
        catch (Exception ex)
        {
            throw new Exception("Unable to retrieve the data from the file.", ex);
        }
    }
}

And, in another library I've been using (related to parsing Excel files), which I cannot change, I have the following kind of method:

        public List<T> doProcess<T>() where T : class, new()
        {
            // the actual work
        }

But I am getting an error in my getValuesFromFile method stating that The type 'T' must be a reference Type to be able to return a List in my method.

I am trying to figure out how to do this to minimize having to write the code for pulling the data from the file into each of the separate derived processor classes.

Is there any way to do this or is this just bad programming for Generics?

Upvotes: 0

Views: 58

Answers (2)

Ren&#233; Vogt
Ren&#233; Vogt

Reputation: 43906

Your otherClass.doProcess() method is declared like

public List<T> doProcess<T>() where T : class, new()

So this requires T to be a reference type and to have a default parameterless constructor.

In the calling method you have only restricted T to implement the FileType interface:

List<T> getValuesFromFile<T>() where T:FileType

This isn't enough. An interface could also be implemented by a value type and it doesn't say anything about constructors. So you'd have to change the constraints to:

List<T> getValuesFromFile<T>() where T: class, FileType, new()

(Note that the class constraint has to be the first in a constraint declaration).

Upvotes: 5

dktaylor
dktaylor

Reputation: 914

You can ensure that T is a reference type by constraining as:

where T : class, FileType

It’s hard for me to understand exactly what you’re trying to do, so I can’t provide guidance on your use of generics more generally.

Upvotes: 4

Related Questions