tags:

views:

111

answers:

4

I'm getting the following compiler error

Cannot convert type 'T' to 'ProjectReportingHandler'

for the line

var projectReport = (ProjectReportingHandler)result.Report;

when trying to compile:

public abstract class ReportingHandler
{
    // Report stuff
}

public abstract class ProjectReportingHandler: ReportingHandler
{
    // Report stuff
    // Project specific report stuff
}

public class ReportInstance<T>
    where T : ReportingHandler
{
    public T Report { get; private set; }
}

public class ReportLibraryEntry<T>
        where T : ReportingHandler
{
    public ReportInstance<T> Create()
    {
        ReportInstance<T> result = new ReportInstance<T>();

        if (result.Report is ProjectReportingHandler)
        {
            var projectReport = (ProjectReportingHandler)result.Report;
            // do stuff with project reports
        }

        return result;
    }
}

Any ideas how to cast the linked generic type property result.Report to a ProjectReportingHandler?

I would have thought the where T : ReportingHandler would have ensured this was possible :(

EDIT: I seem to be getting a few responses that say my accepted answer is incorrect. It works, and I implemented it as follows:

public ReportInstance<T> Create()
{
    ReportInstance<T> result = new ReportInstance<T>();

    ReportingHandler report = result.Report;
    if (report is ProjectReportingHandler)
    {
        var projectReport = (ProjectReportingHandler)report;
        // do stuff with project reports
    }

    return result;
}

Why the down votes for an answer that worked? :(

+3  A: 

T : ReporingHandler does not guarantee that that the conversion is possible. Just because a ProjectReportingHandler is a ReportingHandler doesn't mean the opposite is true.

Nick
A: 

You can "cheat" by first casting result.Report to an object, and then to a ProjectReportingHandler.

TJMonk15
This can throw an `InvalidCastException`.
SLaks
Great, thanks! Seems like this should be a built-in compiler trick though, as I can't see why preventing this with the aforementioned error is useful :s
Codesleuth
@SLaks: Even when I have the code within the `if (result.Report is ProjectReportingHandler)` block?
Codesleuth
It will be a little it slower, since it will cast twice. It's faster to call `as` and check whether it's `null`.
SLaks
+4  A: 

where T : ReportingHandler is not enough.
What should happen if T is some other type that inherits ReportingHandler but not ProjectReportingHandler?

If you're sure that T will always inherit from ProjectReportingHandler, you can change the constraint to where T : ProjectReportingHandler.

If you really want to do it the way you're doing it now, you should first cast to ReportingHandler, like this:

var projectReport = ((ReportingHandler)result.Report) as ProjectReportingHandler;

If T does not inherit ProjectReportingHandler, projectReport will be null.

SLaks
But I have the line `if (result.Report is ProjectReportingHandler)` which will be the containing condition... I don't see why it wouldn't always be a `ProjectReportingHandler` if I check first?
Codesleuth
It will be a little it slower, since it will cast twice. It's faster to call `as` and check whether it's `null`.
SLaks
I see your point, but the speed improvement is a minor difference :) Besides, are you sure the IL is that much different? Would be interesting to see.
Codesleuth
A: 

How about using as:

        ReportInstance<T> result = new ReportInstance<T>();
        var projectReport = result.Report as ProjectReportingHandler;
        if (projectReport != null)
        {
            //do stuff
        }
BFree