none
Inheriting generic classes from base classes with generic parameters. Error converting to base type. RRS feed

  • Question

  • I am trying to get the code below to work, but I can't figure it out. Can someone guide me to solve this issue? The code is ready to be copied to a console application.

    using System;
    using System.Collections.Generic;
     
    namespace ConsoleApp1
    {
        class Program
        {
            static void Main(string[] args)
            {
                Vehicle<Actions> aCar = new Car();  // Error: Cannot Implicitly convert type Car
                                                    // to Vehicle<Actions 
     
                Vehicle<Actions> anAirplane = new Airplane(); // Error: Cannot Implicitly convert type
                                                              // Airplane to Vehicle<Actions
     
                List<Vehicle<Actions>> list = new List<Vehicle<Actions>>()
                {
                    aCar,
                    anAirplane
                };
                
                foreach (var vehicle in list)
                {
                    vehicle.actions.ID = "any";
                    vehicle.actions.PerformAction();
                }
                Console.WriteLine("Good");
            }
        }
     
    
        public interface IVehicle<TActions> where TActions : IActions
        {
            TActions actions { get; set; }
        }
        public class Vehicle<TActions> : IVehicle<TActions> where TActions : Actions
        {
            TActions _actions;
            public TActions actions { get => _actions; set => _actions = value; }
        }
        public class Car : Vehicle<CarActions> 
        {
            public int Wheels { get; set; }
        }
     
        public class Airplane : Vehicle<AirplaneActions> {}
     
        public interface IActions
        {
            string ID { get; set; }
            void PerformAction();
        }
     
        public abstract class Actions : IActions
        {
            public string ID { get ; set; }
            public abstract void PerformAction();
        }
     
    
        public class CarActions : Actions
        {
            int speed;
            public override void PerformAction()
            {
                speed = 50;
            }
        }
     
        public class AirplaneActions : Actions
        {
            int Height;
            public override void PerformAction()
            {
                Height = 5000;
            }
        }
    }

    Wednesday, October 11, 2017 9:53 PM

All replies

  • Greetings MBV800.

    That code looks to be in a real tangle. Before I look at any fixes I have to ask, are you sure (really sure) you need generics? It doesn't look like a job for generics to me.

    Wednesday, October 11, 2017 11:13 PM
  • Agreed. Is there any reason for not using interface with extension method?
    Thursday, October 12, 2017 12:57 AM
    Answerer
  • Thanks Ante

    A Vehicle (the abstract class) has an Action property (Abstract Action:IAction). I need to create many types (classes) that Inherit from vehicle. Each derived class (Car or Airplane) have implement Actions differently (A car moves, breaks. An airplane Flies, lands). What I need is to put all my instances in a collection (Car, Airplane, Train etc) and make generic calls (Vehicle.PerformActions). Without generics, An Airplane and a Car are Vehicles, no problem, but generics lets me pass the type (CarAction or AirplaneAction) when creating a Car or An Airplane.

    Of course my real problem is different, but that is the Idea.

    Even if this is not the right approach, I do think Generics should do the job. The issue has to do with Covalence/Antivalence. I have read that using In/Out when declaring T (<out TAction>) solves the problem, but I couldn't make it work. Also, using In/out, I won't be able to declare a TAction variable read and write. TAction action {get;set} throws a compiling error.

    Thursday, October 12, 2017 10:28 AM
  • As I suspected, it's not a job for generics. And as cheong00 suggested, it's a job for interfaces (although I don't think extension methods are necessary).

    Try something like this.

    using System;
    using System.Collections.Generic;
    
    namespace ConsoleApp1
    {
       class Program
       {
          static void Main(string[] args)
          {
             IVehicle aCar = new Car();  
    
             IVehicle anAirplane = new Airplane(); 
    
             List<IVehicle> list = new List<IVehicle>()
                {
                    aCar,
                    anAirplane
                };
    
             foreach (var vehicle in list)
             {
                vehicle.VehicleActions.ID = "any";
                vehicle.VehicleActions.PerformAction();
             }
             Console.WriteLine("Good");
          }
       }
    
    
    
       public interface IActions
       {
          string ID { get; set; }
          void PerformAction();
       }
    
       public abstract class Actions : IActions
       {
          public string ID { get; set; }
          public abstract void PerformAction();
       }
    
       public class CarActions : Actions
       {
          int speed;
          public override void PerformAction()
          {
             speed = 50;
             Console.WriteLine("Performed action : speed = " + speed.ToString());
          }
       }
    
       public class AirplaneActions : Actions
       {
          int Height;
          public override void PerformAction()
          {
             Height = 5000;
             Console.WriteLine("Performed action : Height = " + Height.ToString());
          }
       }
    
    
       public interface IVehicle
       {
          IActions VehicleActions { get; set; }
       }
    
       public class Car : IVehicle
       {
          IActions  vehicleActions = new CarActions();
          public IActions VehicleActions { get { return vehicleActions; } set { vehicleActions = value; } }
    
          public int Wheels { get; set; }
       }
    
       public class Airplane : IVehicle
       {
          IActions vehicleActions = new AirplaneActions();
          public IActions VehicleActions { get { return vehicleActions; } set { vehicleActions = value; } }
       }
    
    }
    
    

    Thursday, October 12, 2017 10:34 PM
  • As I suspected, it's not a job for generics. And as cheong00 suggested, it's a job for interfaces (although I don't think extension methods are necessary).

    Yup. If there are just methods related to Vehicles, using a base class to provide implementation for common method should be enough.

    However, since C# does not support multiple inheritance, if there need to have further abstraction such as IGoodsVehicle, IPassengerVehicle, etc. , using extension method will probably make the code cleaner (since extension method can only access members that are public, it may not solve all usage problem).

    Friday, October 13, 2017 1:23 AM
    Answerer
  • That works! Thanks Ante.
    Friday, October 13, 2017 1:54 AM
  • No worries. Looking back at the code I posted, I can see one or two places it might be improved, but I'm sure you can work them out.
    Friday, October 13, 2017 2:30 AM