avivr
avivr

Reputation: 2593

'InvalidCastException' while trying to cast concrete object to generic interface

I'm trying to create a class using Activator.CreateInstance and cast it to a generic interface it implements.

Why am I getting 'InvalidCastException' at run time (.Net 4.0)?

Here is the code:

namespace CastingGenerics
{
    class Program
    {
        static void Main(string[] args)
        {
            var typeFromSomewhere = typeof(ActionSomethingValidator);

            // This line throw 'System.InvalidCastException'
            // "Unable to cast object of type 'CastingGenerics.ActionSomethingValidator' to type 'CastingGenerics.IActionValidator`1[CastingGenerics.IAction]'."
            var castingError = (IActionValidator<IAction>)Activator.CreateInstance(typeFromSomewhere);
        }
    }

    internal interface IAction
    {
    }

    internal interface IActionValidator<in T>
        where T : IAction
    {
        bool Validate(T action, out string failure);
    }

    internal abstract class ActionValidator<T> : IActionValidator<T>
        where T : IAction
    {
        public abstract bool Validate(T action, out string failure);
    }

    internal class ActionSomethingValidator : ActionValidator<IActionSomething>
    {
        public override bool Validate(IActionSomething action, out string failure)
        {
            failure = string.Empty;
            return true;
        }
    }

    internal interface IActionSomething : IAction
    {
    }
}

Upvotes: 4

Views: 1571

Answers (2)

Mario Santos
Mario Santos

Reputation: 1

One way is using dynamic.

dynamic smth = Activator.CreateInstance(typeFromSomewhere);

You will lose the autocomplete feature since the editor cannot determine the type at design time. But you still able to invoke the methods just coding by hand. smth.Validate(() => true, "");

Upvotes: 0

O. R. Mapper
O. R. Mapper

Reputation: 20731

What you get is an IActionValidator<IActionSomething>. IActionValidator<IActionSomething> cannot be assigned to IActionValidator<IAction>, because T is marked as an in type parameter.

Imagine, that for an IActionValidator<IAction> variable named v, there is the following Validate method:

Validate(IAction action, out string failure);

Now, if v pointed to an instance of IActionValidator<IActionSomething>, you could pass an IAction instance to the first parameter via v that does not implement IActionSomething. However, exactly the latter would be required for IActionValidator<IActionSomething>. Therefore, the compiler will not let you do this.

Upvotes: 1

Related Questions