0

I have populated an array of type ICanvasEffect with objects of derived classes, such as GaussianBlurEffect, PosterizeEffect, etc.

List<ICanvasEffect> effects = new List<ICanvasEffect>();

effects.Add(new GaussianBlurEffect
{
    BlurAmount = 4.0f,
    BorderMode = EffectBorderMode.Soft,
    Optimization = EffectOptimization.Balanced
});

effects.Add(new PosterizeEffect
{
    RedValueCount = 3,
    GreenValueCount = 3,
    BlueValueCount = 3
});

I now want to set the input sources of those effects in an abstract way. For example,

effects[0].Source = inputBitmap;
effects[1].Source = effects[0];

However, in order to call the Source property, I must provide knowledge of the specific class. For example,

(effects[0] as GaussianBlurEffect).Source = inputBitmap;
(effects[1] as PosterizeEffect).Source = effects[0];

How could this be done in an abstract way as in, for example, this fashion?

(effects[0] as effects[0].GetType()).Source = inputBitmap;
(effects[1] as effects[1].GetType()).Source = effects[0];
0

2 Answers 2

1

That's a pretty good example for the Builder Design Pattern. It could looke like this:

using System.Drawing;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {
        Bitmap inputBitmap = default;
        var canvasBuilder = new CanvasBuilder()
            .AddEffect(new CanvasEffect1())
            .AddEffect(new CanvasEffect2());
        Bitmap bitmap = canvasBuilder.Build(inputBitmap);
    }
}

public interface ICanvasBuilder
{
    ICanvasBuilder AddEffect(ICanvasEffect effect);
    Bitmap Build(Bitmap input);
}

public class CanvasBuilder : ICanvasBuilder
{
    private List<ICanvasEffect> _effects = new List<ICanvasEffect>();
    
    public ICanvasBuilder AddEffect(ICanvasEffect effect)
    {
        _effects.Add(effect);
        return this;
    }

    public Bitmap Build(Bitmap input)
    {
        foreach (var effect in _effects)
        {
            effect.ApplyEffect(input);
        }

        return input;
    }
}

public interface ICanvasEffect
{
    Bitmap ApplyEffect(Bitmap input);
}

public class CanvasEffect1 : ICanvasEffect
{
    public Bitmap ApplyEffect(Bitmap input)
    {
        //modify bitmap
        return input;
    }
}

public class CanvasEffect2 : ICanvasEffect
{
    public Bitmap ApplyEffect(Bitmap input)
    {
        //modify bitmap
        return input;
    }
}

dotnetfiddle: https://dotnetfiddle.net/W1UBlL

Sign up to request clarification or add additional context in comments.

Comments

1

It would have been smarter if the authors of GaussianBlurEffect, PosterizeEffect etc. had used some common interface which included an IGraphicsEffectSource Source { get; set; } member. Then you could have utilized that interface.

However, that does not seem to be the case.

The syntax you propose:

(effects[0] as effects[0].GetType()).Source = inputBitmap;
(effects[1] as effects[1].GetType()).Source = effects[0];

is not legal, of course. The allowed thing corresponding to this, is:

((dynamic)effects[0]).Source = inputBitmap;
((dynamic)effects[1]).Source = effects[0];

When you use the dynamic keyword, the binding of the member .Source is postponed until run-time. So the C# compiler will produce CIL bytecode that will search for a member .Source, given the run-time type (similar to the .GetType() in your attempt), and if found, will attempt the assignment (which is going to correspond to calling a set accessor).

dynamic has a number of disadvantages, of course. Checks that are normally done when you compile your C#, are with dynamic postponed to run-time, which can lead to fails or slower execution.

1 Comment

Cool, thanks! So the abstraction I was hoping for is possible, however, I'd like to see how well the custom video effect will run with 20 - 30 different effects in the array. And using an older Core i3 laptop...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.