How to override generic method with derived type in c#

11,342

Solution 1

I'm making a leap here, but it sounds like you intend to have multiple "services", each with an associated parameter type.

Putting a type parameter on the method, as you have done in the example, forces all implementations of that method to be polymorphic. (The technical term for this is higher-rank quantification.)

Instead, you should associate the type parameter with the service itself. This allows a given implementation of the contract to declare which parameter type it's associated with. While you're at it, I wouldn't bother with the base classes or the type bounds.

interface IService<in T>
{
    void ApplyChanges(T param);
}

class Param1
{
    public int X { get; set; }
}
class Service1 : IService<Param1>
{
    public void ApplyChanges(Param1 param)
    {
        param.X = 123;
    }
}

class Param2
{
    public int Y { get; set; }
}
class Service2 : IService<Param2>
{
    public void ApplyChanges(Param2 param)
    {
        param.Y = 456;
    }
}

Solution 2

You shouldnt impose stronger constraints for method overrides. An overridden method should expand the possible input parameters and reduce the possible outcomes. Otherwise it breaks Liskov Substitution Principle. C# does not allow you to do that.

That said, if you really want it, you could. You won't get compiler warnings in the calling code though. Use that solution if you cannot change the base class.

public class Service<TParam> : Service where TParam : ParamA
{
    public override void ApplyChanges<T>(T parameters)
    {
        Console.WriteLine((parameters as TParam).Param2);
    }
}

A better solution would be to add a type parameter to ServiceBase and IService.

public interface IService<TParam>
   where TParam : ParamBase
{
    void ApplyChanges(TParam parameters);
}

public abstract class ServiceBase<TParam> : IService<TParam>
    where TParam : ParamBase
{
    public virtual void ApplyChanges(TParam parameters)
    { }
}
public class Service : ServiceBase<ParamA>
{
    public override void ApplyChanges(ParamA parameters)
    {
        Console.WriteLine(parameters.Param2);
    }
}
Share:
11,342

Related videos on Youtube

Adolfo Perez
Author by

Adolfo Perez

Currently developing and maintaining SAAS Human Capital Management web systems and learning about latest technologies and design patterns. Interested in Javascript, TypeScript, UI automation, C#, EntityFramework, Cloud services like Azure/AWS, performance optimization,dotnet Core, instrumentation.

Updated on September 15, 2022

Comments

  • Adolfo Perez
    Adolfo Perez over 1 year

    I have the following classes:

    public interface IService
    {
        void ApplyChanges<T>(T parameters) where T : ParamBase;
    }
    
    public class ServiceBase : IService
    {
        public virtual void ApplyChanges<T>(T parameters) where T : ParamBase
        { }
    }
    public abstract class Service : ServiceBase
    {
        public override void ApplyChanges<T>(T parameters) where T : ParamBase
        {
            Console.WriteLine(parameters.Param2);
            //Apply changes logic here...
        }
    }
    
    public abstract class ParamBase
    {
        public string Param1 { get; set; }
    }
    
    public class ParamA : ParamBase
    {
        public string Param2 { get; set; }
    }
    

    Here my test main class:

    void Main()
    {
      var service = new Service();
      var paramA = new ParamA();
      paramA.Param2 = "Test2";
      service.ApplyChanges<ParamA>(paramA);
    }
    

    What is wrong with that implementation? How can I access parameters.Param2from the overriden ApplyChanges method in my Service class?

    The general idea is that I have a ServiceBase and I want to be able for its derived classes to pass different parameter types to the ApplyChanges method.