top of page

Generics - generic containers List<T>

  • Writer: Renee Li
    Renee Li
  • Oct 18
  • 2 min read

Mini series 2: interface IFilter <T>


  • image type : IFilter <Image>

  • video type :  IFilter <Video>

  • IFilter interface class, including void Add Filter

  • main


namespace GP3
{
    public interface IFilter<T>
    {
        void AddFilter(T target);
    }
    
}
namespace GP3
{
    public class Image: IFilter<Image>
    {
        public string _imageName { set; get; }

        public Image(string imageName)
        {
            _imageName = imageName;
        }

        public void AddFilter(Image target)
        {
            Console.WriteLine("Image interface filter is added to " + target._imageName);
        }


    }
}
namespace GP3
{
    public class Video : IFilter<Video>
    {
        public string _videoName { set; get; }

        public Video(string videoName)
        {
            _videoName = videoName;
        }

        public void AddFilter(Video target)
        {
            Console.WriteLine("Video interface filter is added to " + target._videoName);
        }
    }
}
using System.Reflection;

namespace GP3
{
    internal class Program
    {
        static void Main(string[] args)
        {
            var img = new Image("MyImage");
            var vid = new Video("MyVideo");

            IFilter<Image> imageFilter = new Image("MyImage"); 
            IFilter<Video> videoFilter = new Video("MyVideo");
            imageFilter.AddFilter(img);
            videoFilter.AddFilter(vid);   

        }
    }
}

So, this time, we created two seperate list, one for image and one for video, compared to mini series 1 - creating a list of IFliter and add both image objects and video objects into the same list.


🎬 Mini Series 1: Unified List of IFilter

  • You had a single list like List (non-generic)

  • You added both Image and Video objects into it

  • This required casting or runtime checks to apply filters correctly

  • It was flexible but not type-safe

Pros:

  • One list, easy to manage

  • Can iterate over all filters uniformly

Cons:

  • Loses compile-time type safety

  • You need to check types manually (if (filter is IFilter))

  • Risk of runtime errors if mismatched


🖼️🎥 This Version: Two Typed List


List<IFilter<Image>> imageFilters = new List<IFilter<Image>>();
List<IFilter<Video>> videoFilters = new List<IFilter<Video>>();

Pros:

  • Strong type safety: compiler enforces correct usage

  • No casting or type checks needed

  • Easier to reason about filter behavior per media type


Cons:

  • Slightly more boilerplate (two lists)

  • Harder to treat filters as a unified concept unless you abstract further


Architectural Insight


You're now treating Image and Video as distinct domains, each with its own filter pipeline. This is perfect if:


  • Filters behave differently per media type

  • You want to extend each domain independently

  • You value clarity and safety over raw flexibility

If you ever want to unify them again, you could introduce a base interface.


A base interface is one direction to explore. I am wondering for mini series 1, if i use delegate and events, would that avoid casting ?

Yes — using delegates and events in Mini Series 1 can absolutely help you avoid casting 🎯. - Copilot

In following mini series, I will build a simple base interface class, and I will go back explore delegates and events and to see if we can try to avoid casting and reduce run time cost for mini series 1.


Stay tuned!


Comments


bottom of page