Allow method to work with all inherited types

152 Views Asked by At

I have a class A from which B and C inherit. I also have lists of B and C like so: List<B> listB and List<C> listC.

I want to add elements to these lists but only after I do some logic. I have made a method that takes a list of any type and a related item to add.

public void AddItemToList<T>(List<T> item_list, T new_item)
{
    //do logic with properties of A...
}

I need to be able to use this method with both lists, like so:

AddItemToList<B>(listB, new B());
AddItemToList<C>(listC, new C());

However, since the type is generic, I cannot do the logic I want inside the method using A's properties.

If I use type A in the method, then I cannot pass the lists or items without casting them first.

Is there a way to set the type so I can pass matching parameters while still being able to do logic inside the method?

2

There are 2 best solutions below

0
On BEST ANSWER

You can put a constrain on T, using where in method declaration

See where (generic type constraint)

using System;
using System.Collections.Generic;

class A
{
    public int PropA;
}

class B : A
{
}

class C : A
{
}

class NotDerivedFromA
{
}

class Foo
{
    // where T:A force T to be A or a derived class
    public void AddItemToList<T>(List<T> item_list, T new_item) where T:A
    {
        Console.WriteLine(new_item.PropA);
    //do logic with properties of A...
    }
}

public class Program
{
    public static void Main()
    {
        List<A> listA = new();
        List<B> listB = new();
        List<C> listC = new();
        
        Foo foo = new();
        
        foo.AddItemToList<A>(listA, new A());
        foo.AddItemToList<B>(listB, new B());
        foo.AddItemToList<C>(listC, new C());
        
        // this doen't compile:  NotDerivedFromA doesn't satisfy the constraint
        //foo.AddItemToList<NotDerivedFromA>(new List<NotDerivedFromA>(), new NotDerivedFromA());
        
        Console.WriteLine("Hello World");
    }
}
1
On

If your generic method needs to perform type-specific functions, then it isn't generic. However, you could take a functional approach and pass in an Action<T> delegate that does the type-specific work:

public void AddItemToList<T>(List<T> item_list, T new_item, Action<T> effect)
{
    effect(new_item);
    // etc
}

then call it:

// `x` below is inferred to be of type `int`
AddItemToList(new List<int>(), 0 ,x => Console.WriteLine(x + 1));