Home > front end >  Using generics to get correct return type
Using generics to get correct return type

Time:09-17

I'm trying to generate a filter with a generic method. Filter is an abstract class. SomeFilter class would extend Filter. I want a method like this:

protected Filter GenerateFilter<T> () where T : Filter
{
    if (T == SomeFilter) 
    {
        return new SomeFilter();
    }
}

EDIT: I'm new to C#, coming from Java. These solutions have helped me a lot in understanding C# generics. Thanks for the help. I will indeed proceed with a FilterFactory. I had hoped i might be able to pull it off with generics, but a factory is still the better thing to implement here.

Thanks!

CodePudding user response:

You could add the new() constraint to the T type parameter and change you method like so:

protected Filter GenerateFilter<T>() where T : Filter, new()
{
        return new T();
}

CodePudding user response:

Use Reflection to create instance

protected Filter GenerateFilter<T>() where T : Filter
{
    return Activator.CreateInstance<T>();
}

CodePudding user response:

I think you are looking at checking for each individual case

    public static T Generate<T>() where T: Filter
    {
        var t = typeof(T);
        if (t == typeof(SomeFilter))
        {
            return new SomeFilter() as T;
        }
        if (t == typeof(OtherFilter))
        {
            return new OtherFilter() as T;
        }
        throw new NotSupportedException();
    }

which can be part of a class hierarchy with known types.

This is going to fall flat if the filters come from a plug-in situation which means not all concrete types are known at compile time. That would require a different architecture, which the op hasn't stated is required.


An alternate solution is each concrete type has a default constructor, is to use new()

    public static T Generate<T>() where T: Filter, new()
    {
        return new T();
    }

A third option is to use a deferred type in the filter class just a follows:

static class Program
{
    static void Main(string[] args)
    {
        SomeFilter filter = Filter<SomeFilter>.Generate();
        SomeFilter also = filter.Copy();
        filter.Combine(also);
    }
}


public abstract class Filter<TFilter> where TFilter: Filter<TFilter>, new()
{
    public static TFilter Generate() 
    {
        return new TFilter();
    }

    public TFilter Copy() => this.MemberwiseClone() as TFilter;

    public abstract void Combine(TFilter other);
}
public class SomeFilter : Filter<SomeFilter>
{
    public float Alpha { get; set; }

    public override void Combine(SomeFilter other)
    {
        this.Alpha *= other.Alpha;
    }
}
public class OtherFilter : Filter<OtherFilter>
{
    public int Strength { get; set; }

    public override void Combine(OtherFilter other)
    {
        this.Strength = Math.Max(Strength, other.Strength);
    }
}

The advantage of the base class to know the type of the derived class in TFilter is that it cam be used in methods, such as Combine() and Copy() above and it will resolve to the correct type when implemented.

  • Related