2010-03-14 15 views
6

Extiendo el control ImageBox desde EmguCV. La propiedad Image del control se puede establecer en cualquier elemento que implemente la interfaz IImage.C# Métodos de llamada en clases genéricas

Todos los siguientes implementar esta interfaz:

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

Ahora quiero llamar al método Draw en el objeto del tipo anterior (lo que nunca puede ser).

El problema es cuando accedo a la propiedad de la imagen, el tipo de retorno es IImage. IImage no implementa el método Draw, pero sí lo hace todo lo anterior.

Creo que puedo convertir el objeto del tipo IImage en uno de los anteriores (el correcto) y puedo acceder al método Draw. ¿Pero cómo sé cuál es el correcto? Si tiene una mejor manera de hacerlo, sugiérala también.

EDITAR

Lo sentimos, pero se me olvidó mencionar una pieza importante de información. El método Draw para cada una de las clases anteriores toma un argumento diferente. Por ej. Draw para Image<Bgr, Byte> toma un argumento de tipo Bgr y el Draw para Image<Hsv, Byte> toma un argumento de tipo Hsv en su lugar.

+0

¿Tiene acceso al código de imagen e imagen? –

+0

EmguCV es un proyecto de código abierto, aunque realmente prefiero usar sus binarios :) – Aishwar

+0

No parece que la interfaz/implementación de la imagen esté bien diseñada. –

Respuesta

0

¿Qué tal algo como esto:

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

    // handle the other types the same way. 
} 
+3

Creo que es mejor tener una implementación en lugar de muchos ifs. –

+2

Esto es solo pedir código descuidado. Ahora para cada tipo, tendrá que agregar el código en varios lugares. Probablemente sea mejor extrapolar esta lógica, y toda la lógica para los diferentes tipos de imágenes, en algún tipo de renderizador que hacer algo como esto. –

+0

Acepto que hay otras buenas respuestas y esto en general puede llevar a un código muy descuidado. Pero en mi caso, solo tengo que hacerlo una vez y no quiero editar los archivos fuente EmguCV. Usé esto, así que lo marcaré como aceptado. – Aishwar

1

Si he entendido bien - implementa la clase imagen Drenaje método. No sé cómo va a utilizarlo, pero se puede hacer de esta manera:

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

El principal problema sobre el anterior es que el llamador del método anterior debe especificar el T1 y T2 tipos.

Si no tiene control sobre la interfaz de IImage y sus implementaciones, entonces creo que va a elegir entre dos soluciones: especificar tipos T1 y T2 o tener ifs/switches con todas las implementaciones de IImage posibles.

Si tiene acceso a la interfaz e Imagen clase IImage continuación, se debe añadir la interfaz genérica IImage y añadir el método de dibujo para ella.

+0

de esta manera necesita diferentes métodos para diferentes tipos genéricos. – JohnIdol

+0

¿Por qué? Simplemente llama al método anterior con los parámetros de tipo necesarios. –

0

Si está seguro de que la Imagen < T, U > que tendrá (independientemente de los tipos) tendrá el método Draw, puede utilizar la reflexión y cortar alrededor de él:

lo haría como un método de extensión:

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

un poco de un truco, pero por otra parte, yo diría que la API no está diseñado adecuadamente. Al menos debería haber alguna clase de Drawer o algo que supiera cómo actuar en una imagen.

+0

Esto sería muy lento. –

+0

Optimización prematura mucho? – BFree

+0

No, los reflejos son lentos y las soluciones propuestas no son una forma natural de cómo deben usarse las reflexiones. –

1

Deberá tener una interfaz compartida que agregue Draw().

3

Agregue IDrawableImage que hereda de IImage.

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

A continuación, puede hacer lo siguiente:

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

para que coincida con la aclaración anterior:

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

continuación, si se conoce el tipo:

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

si no lo haces

var value = new Hvr(); 
var drawableImage = container.Image as IDrawableImage; 
if (drawableImage != null) 
    drawableImage.Draw(value); 
+2

Es una buena práctica crear interfaces para este tipo de problemas. Comprobar cada implementación (como en el ejemplo de Adel) viola el principio Abierto/cerrado (http://en.wikipedia.org/wiki/Open/closed_principle) y crea un alto acoplamiento (http://en.wikipedia.org/wiki/Coupling_ % 28computer_science% 29). Con esta interfaz, puede crear un nuevo tipo 'Image ' y usar eso sin alterar ningún código que llame al método 'Draw'. – Ronald

+0

Eso es exactamente por lo que sugerí este método, haciendo las declaraciones if grandes me ha mordido en la parte posterior más de lo que puedo contar a lo largo de los años, especialmente cuando empiezas a hacer esto en todas partes. De repente necesitas un artículo interno de wiki sobre cómo agregarle un nuevo tipo porque toca tanto código. –

0

A su pregunta le falta una información crítica: el código que desea escribir.

Necesitamos saber cómo piensa escribir el código que llama al método Draw(...).

0

O bien, puede utilizar métodos dinámicos y arriesgarse.

Cuestiones relacionadas