1

When we try to upcast from a Generic Type class to a formal implementation it gives a casting error.

In the code below you can see that I have a FormalClass that is an implementation of a GenericTypeClass. When I try to up cast from the GenericTypeClass to a FormalClass it it gives this error:

"[System.InvalidCastException: Unable to cast object of type 'GenericTypeClass`1[TestType]' to type 'FormalClass'.]"

I know that this will not work but if you need to do an up cast what is the best way to solve it? Automapper? Json serialization? Other?

Below is a dotnetfiddle ( https://dotnetfiddle.net/LLg0vp ) example:

using System;

public class Program
{
    public static void Main()
    {
        var a = new GenericTypeClass<TestType>();

        var b = a as FormalClass;
        if (b == null)
            Console.WriteLine("'a as Formal' Is NULL");

        try
        {
            var c = (FormalClass)a;
        }
        catch (Exception ex)
        {
            Console.WriteLine("'(FormalClass)a' gives this error: " + ex.Message);
        }
    }
}

public class FormalClass : GenericTypeClass<TestType>
{
}

public class GenericTypeClass<T>
    where T : class, IType
{
}

public class TestType : IType
{
}

public interface IType
{
}
Diogo Luis
  • 228
  • 2
  • 9
  • 1
    why should that cast work? a `GenericTypeClass` != `FormalClass` – Selman Genç Aug 27 '18 at 09:38
  • I know that it will not work, I was searching for the best solution when you want to do something like that. Like using automapper... – Diogo Luis Aug 27 '18 at 09:59
  • If upcasting is all you need, just replace `var a =` with `object a =` or create a base class that `GenericTypeClass` inherits from and `BaseClass a =` should do it – vc 74 Aug 27 '18 at 13:02

2 Answers2

1

You can't accomplish this with inheritance. Once an object is created with a type of GenericTypeClass<TestType> it can never become a FormalClass.

Options:

  1. Investigate ways to create a FormalClass instead of a GenericTypeClass<TestType>.
    • This could be simple or complex depending on the flow of your code.
  2. Create a new FormalClass and use Automapper to copy property values into it
    • Changes to a property in the new FormalClass object would have no effect on the original Generic object.
  3. Instead of making FormalClass inherit from GenericTypeClass<TestType>', make it a wrapper for aGenericTypeClass' and pass in the `GenericTypeClass' in the constructor.
    • Any new property added to the Generic class would have to be added to the FormalClass

I have included a code sample for the wrapper method.


using System;

public class Program
{
    public static void Main()
    {
        var a = new GenericTypeClass<TestType>();
        var b = new FormalClass(a);
        a.Name = "NameA";
        b.Name = "NameB";
        Console.WriteLine(a.Name);
        Console.WriteLine(b.Name);
    }
}

public class FormalClass
{
    GenericTypeClass<TestType> _inner;
    public FormalClass(GenericTypeClass<TestType> parameter)
    {
        _inner = parameter;
    }

    public string Name
    {
        get
        {
            return _inner.Name;
        }

        set
        {
            _inner.Name = value;
        }
    }
}

public class GenericTypeClass<T>
    where T : class, IType
{
    public string Name
    {
        get;
        set;
    }
}

public class TestType : IType
{
}

public interface IType
{
}
Grax32
  • 3,986
  • 1
  • 17
  • 32
  • This is a nice solution the wrapper. In my case, I come to this problem because I was refactoring a Class that I needed to make it Generic with a Type Parameter, and since it was used everywhere and I didn't wanted to pass the Type to it, I just derive it from the Generic one using the same name to keep the refactoring simple. – Diogo Luis Aug 27 '18 at 13:35
  • The key is looking at where you create the instance. If you create it as a 'FormalClass' in the first place, you can use it as a 'GenericTypeClass'. If you have a 'GenericTypeClass' that was originally created as a FormalClass then you can use the as operator (or a cast) to refer to it. But if you can't create it as a FormalClass, the wrapper is a good option. – Grax32 Aug 27 '18 at 13:53
0

You example can be simplified as follows (note that generics don't have anything to do here):

void Main()
{
    var a = new BaseClass();

    var b = a as DerivedClass;
    if (b == null)
        Console.WriteLine("'a as Derived' Is NULL");
}


public class BaseClass
{
}

public class DerivedClass : BaseClass
{
}

...and sure enough, that's never going to work. Derived classes can be casted back to the base class, but not the other way around.

Konamiman
  • 49,681
  • 17
  • 108
  • 138
  • Also, you might want to take a look here: [Inheritance in C# and .NET @ Microsoft docs](https://learn.microsoft.com/en-us/dotnet/csharp/tutorials/inheritance) – Konamiman Aug 27 '18 at 09:46
  • I know that it will not work, I was searching for the best solution when you want to do something like that. Like using automapper... – Diogo Luis Aug 27 '18 at 09:57