views:

278

answers:

7

I am extending the ImageBox control from EmguCV. The control's Image property can be set to anything implementing the IImage interface.

All of the following implement this interface:

Image<Bgr, Byte>
Image<Ycc, Byte>
Image<Hsv, Byte>

Now I want to call the Draw method on the object of the above type (what ever it may be).

The problem is when I access the Image property, the return type is IImage. IImage does not implement the Draw method, but all of the above do.

I believe I can cast the object of type IImage to one of the above (the right one) and I can access the Draw method. But how do I know what the right one is? If you have a better way of doing this, please suggest that as well.

EDIT

Sorry, but I forgot to mention an important piece of information. The Draw method for each of the above class takes one different argument. For e.g. Draw for Image<Bgr, Byte> takes an argument of type Bgr and the Draw for Image<Hsv, Byte> takes an argument of type Hsv instead.

+1  A: 

How about something like this:

void foo( IImage image )
{
    if ( image is Image<Bgr, Byte> )
    {
        ((Image<Bgr, Byte>)(image)).Draw();
    }

    // handle the other types the same way.
}
Adel Hazzah
I think it is better to have one implementation instead of many ifs.
Andrew Bezzub
This is just begging for sloppy code. Now for every type you are going to have to add the code in multiple places. It would probably be better to extrapolate this logic, and all the logic for the different image types, into some sort of renderer than do something like this.
Tom Anderson
I agree there are other good answers and this in general may lead to very sloppy code. But in my case, I just have to do it once and I don't want to edit the EmguCV source files. I used this, so I will mark this as accepted.
aip.cd.aish
+1  A: 

If I understood you correctly - Image class implements draw method. I don't know how you are going to use it, but you can do in this way:

private void DrawImage<T1, T2>(Image<T1, T2> image)
{
    image.Draw();
}

The main problem about above is that the caller of the above method should specify the T1 and T2 types.

If you don't have control about IImage interface and its implementations then I think you will be choosing from two solutions: specify T1 and T2 types or having ifs/switches with all possible IImage implementations.

If you have access to the IImage interface and Image class then you should add generic IImage interface and add Draw method to it.

Andrew Bezzub
this way you need different methods for different generic types.
JohnIdol
Why? You just call the above method with necessary type parameters.
Andrew Bezzub
A: 

If you're sure that the Image<T,U> that you'll have (regardless of the types) will have the Draw method, you can use reflection and hack around it:

I would do it as an extension method:

public static void Draw(this IImage image)
{
   var method = image.GetType().GetMethod("Draw");
   if(method != null)
   {
      method.Invoke(image,null);
   }
}

A bit of a hack, but then again, I would say that the API isn't properly designed. There should at least be some Drawer class or something that would know how to act on an image.

BFree
This would be very slow.
Andrew Bezzub
Premature optimization much?
BFree
No, reflections are slow and proposed soltions is not a natural way of how reflections should be used.
Andrew Bezzub
If you create a delegate from the MethodInfo and cache that instead of looking it up each time, calling it repeatedly won't be slow at all.
Ben Voigt
+1  A: 

You'll should have a shared interface that adds Draw().

s_hewitt
+3  A: 

Add an IDrawableImage that inherits from IImage.

public interface IDrawableImage : IImage
{
   void Draw(object val);
   void Draw();
}

Then you can simply do the following:

var drawableImage = container.Image as IDrawableImage;
if (drawableImage != null)
    drawableImage.Draw();

To match your clarification above:

public interface IDrawableImage<T, B> : IDrawableImage where B : byte
{
    void Draw<T>(T val);
}

then if you know the type:

var value = new Hvr();
var drawableImage = container.Image as IDrawableImage<Hvr, Byte>;
if (drawableImage != null)
    drawableImage.Draw(value);

if you don't

var value = new Hvr();
var drawableImage = container.Image as IDrawableImage;
if (drawableImage != null)
    drawableImage.Draw(value);
Tom Anderson
It's a best practice to create interfaces for these kind of problems. Checking each implementation (as in Adel's example) violates the Open/closed principle (http://en.wikipedia.org/wiki/Open/closed_principle) and creates high coupling (http://en.wikipedia.org/wiki/Coupling_%28computer_science%29). With this interface, you can create a new `Image<T, Byte>` type and use that without altering any code that calls the `Draw` method.
Ronald
Thats exactly why I suggested this method, doing the large if statements has bit me in the rear more than I can count over the years, especially when you start doing this everywhere. All of the sudden you need an internal wiki article on how to add a new type to it because it touches so much code.
Tom Anderson
A: 

Your question is missing a critical piece of information: the code you would like to write.

We need to know how you intend to write the code which calls the Draw(...) method.

Bryan Watts
A: 

Or, you can use dynamic methods and take your chances.

portland