Michael Kingsmill
Michael Kingsmill

Reputation: 1863

Generic Mapping Method fails to convert to concrete types

I am trying to create a generic mapping function that will take in various types that all inherit from NSReportBase and then new up the appropriate object and return it. So far, I have the following:

internal static T BuildNamingStandardType<T>(DataRow dr) where T : NSReportBase, new()
{
    T newNamingStandardReport = null;

    if (typeof(T) is NSPipelineSystems)
        newNamingStandardReport = new NSPipelineSystems(dr["Column1"], dr["Column2"]);
    else if (typeof(T) is NSPipelineSegmentGroups)
        newNamingStandardReport = new NSPipelineSegmentGroups(dr["Column3"]);

    return newNamingStandardReport; 
}

However, I am getting an error that each concrete type cannot be implicitly converted to type 'T'. Given that T is known by the compiler to be of type 'NSReportBase', I am not sure I understand the issue here, let alone how to fix it.

EDIT: I may have over simplified the example. The challenge is that the constructors do not actually take no arguments, but different numbers and types of columns from the DataRow that is a parameter to the method. I know that I could do this polymorphically, but I would like to avoid exposing the DataRow column names to my business logic by moving this method into the respective domain objects.

Upvotes: 1

Views: 184

Answers (3)

usr
usr

Reputation: 171206

Given that T is known by the compiler to be of type 'NSReportBase'

It is not known to the compiler. The C# language does not define that the compiler must derive types through data-flow tracing (in fact it is forbidden to compile this). Humans can see this fact, the language is defined not to see it (but tools like Resharper can see it as a utility).

Solution: First cast to object, then to the concrete type. This method still feels like a hack to me. Maybe you should evaluate whether you should use generics in the first place. The purpose of generics is that your generic method does not need to care about the concrete type.

Upvotes: 1

Dennis
Dennis

Reputation: 37780

internal static T BuildNamingStandardType<T>(DataRow dr) where T : NSReportBase, new()
{
    return new T(); 
}

But it isn't clear, why there's a dr parameter.

Upvotes: 0

LunicLynx
LunicLynx

Reputation: 1098

As long as the type your trying to instantiate has a default constructor you could use the new constraint.

where T : new()

then you are able to

var instance = new T();

Also the error comes from the fact that the Compiler only knows that T is of Type NSReportBase but when using T becomes either NSPipelineSystems or NSPipelineSegmentGroups and you cannot assign NSPipelineSystems to NSPipelineSegmentGroups or vice versa, this is why you get that error.

If you want to solve that you have to change

T newNamingStandardReport = null;

to

NSReportBase newNamingStandardReport = null;

and cast the return value manually to (T).

Upvotes: 2

Related Questions