Jonathan Mc Namee
Jonathan Mc Namee

Reputation: 474

Reflection - casting object to interface<interface>

Following on from How to reflect an interfaced type<t> at runtime I have an instance of a type that I know is inherited from base type DataPointProcessorBase This base class is relatively simple

public abstract class DataPointProcessorBase<T> : IDataPointProcessor<T> where T : class, IDataPointInput, new()
{            
    public abstract DataPointOutputBase GetOutput(T input);
}

Age_Input implements the interface and Age_Processor is set up to receive it

public class Age_Input : DataPointInputBase, IDataPointInput
{
    public int AgeExact { get; set; }    
}
public class Age_Processor : DataPointProcessorBase<Age_Input> 
{
    ...
}

Using reflection, I'm half way to casting it properly so I can call GetOutput()

Any ideas why I can't get into first if statement below?

var instance = Activator.CreateInstance(type);

if (instance is IDataPointProcessor<IDataPointInput>)//why can I not cast interface here?
{
    //false        
}

if (instance is IDataPointProcessor<Age_Input>)//hard-coded - works fine
{
    var processor = instance as IDataPointProcessor<Age_Input>;
    Age_Input temp = item as Age_Input;
    if (temp is IDataPointInput)
    {
        //also true
    }
    var result = processor.GetOutput(temp);
}

Upvotes: 2

Views: 877

Answers (3)

Jonathan Mc Namee
Jonathan Mc Namee

Reputation: 474

I've solved this and How to reflect an interfaced type<t> at runtime by avoiding the issue entirely by not using reflection. Full answer on that page if anybody interested

Thanks all for your time

@Eric I had indeed found your article beforehand, but my head hurt at that point!

Upvotes: 0

Eric Lippert
Eric Lippert

Reputation: 660024

This question is asked every day. One more time!

Is a basket of apples usable when you need a basket of fruit? No.

Why not? Because you can put a banana into a basket of fruit, but you cannot put a banana into a basket of apples.

Therefore you cannot use a basket of apples where a basket of fruit is needed.

Similarly, a basket of fruit is not usable as a basket of apples, because it might already contain a banana.

The relationship "a C<X> can be used as a C<Y> if an X can be used as a Y" is called covariance, and C# only supports covariance in a very limited set of circumstances:

  • C<T> must be an interface or delegate
  • The interface or delegate declaration must be marked as safe for variance.
  • The compiler must successfully verify that the variance declaration is guaranteed to be safe.
  • Both X and Y must be reference types.

In your case, you have got the first and fourth properties but you have not got the second and third.

Mark IDataPointProcessor<T> like this:

interface IDataPointProcessor<out T>

which means roughly "T is used only at output positions, never input positions". If baskets have no ability to add fruit then the objection -- you can't put a banana into a basket of apples -- vanishes, and it becomes legal.

If the compilation succeeds then covariance will start working on IDataPointProcessor. If not, you're probably using T in a position where a T can flow in. The rules are a bit more subtle than I'm summarizing here; if you need a detailed description, I wrote one here: https://blogs.msdn.microsoft.com/ericlippert/2009/12/03/exact-rules-for-variance-validity/

That's why you can use an IEnumerable<Giraffe> as an IEnumerable<Animal> -- all four conditions are met.

Upvotes: 9

David
David

Reputation: 231

From what I understand, The way generic types work in the C# compiler is that the strongly typed types that are used in those generic parameters at compile time (meaning they are used in your code) are generated dynamically as strongly typed classes (Possibly on the MSIL layer).

So during run time your object doesn't have inherited Type with a generic type but instead a inherited type of a strong type.

You can build a switch case of each possible strongly typed type and try to cast to it.

Upvotes: -1

Related Questions