.NET Fiddle

CSharp · Console

/Program.cs

using System;
using System.Collections.Generic;
					
public class Program
{
	public static void Main()
	{
		Console.WriteLine("Hello World");
		List<TipoBase> listTipoBase = new List<TipoBase>(); 
		listTipoBase.Add(new TipoBase(){Value = 1});
		listTipoBase.Add(new TipoBase() { Value = 2 });
		
		List<Tipo1> listTipo1 = new List<Tipo1>();
		listTipoBase.Add(new Tipo1() { Value = 1 });
		listTipoBase.Add(new Tipo1() { Value = 2 });
		
		List<Tipo2> listTipo2 = new List<Tipo2>();
		listTipoBase.Add(new Tipo2() { Value = 1 });
		listTipoBase.Add(new Tipo2() { Value = 2 });
		
		ProgramTest program = new ProgramTest();
		
		program.FacaAlgoComTipoBase(listTipoBase);
		program.FacaAlgoComTipoBase(listTipo1);
		program.FacaAlgoComTipoBase(listTipo2);
	}
}

public class ProgramTest{
	
	
	public void FacaAlgoComTipoBase<T>(List<T> lista) where T : TipoBase
	{
		foreach (T t in lista)
		{
			// assim eu posso chamar o método PrintValue(), garantido pela class TipoBase
			Console.WriteLine(t.PrintValue());
		}
	}	
}

public class TipoBase
{
    public int Value { get; set; }

    public virtual string PrintValue()
    {
        return "O valor na class TipoBase é: " + Value;
    }
}

public class Tipo1 : TipoBase
{
    public override string PrintValue()
    {
        return "O valor na class Tipo1 é: " + Value;
    }
}

public class Tipo2 : TipoBase
{
    public override string PrintValue()
    {
        return "O valor na class Tipo2 é: " + Value;
    }
}
;