2010-03-14 47 views
6

Tôi đang mở rộng điều khiển ImageBox từ EmguCV. Thuộc tính Image của điều khiển có thể được đặt thành bất kỳ điều gì đang triển khai giao diện IImage.C# Gọi phương thức trong lớp học chung

Tất cả các cài đặt giao diện này như sau:

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

Bây giờ tôi muốn gọi phương thức Draw trên đối tượng của các loại trên (những gì bao giờ nó có thể được).

Vấn đề là khi tôi truy cập thuộc tính Hình ảnh, kiểu trả về là IImage. IImage không thực hiện phương thức Draw, nhưng tất cả các phương pháp trên đều thực hiện.

Tôi tin rằng tôi có thể truyền đối tượng thuộc loại IImage đến một trong các bên trên (bên phải) và tôi có thể truy cập phương thức Draw. Nhưng làm thế nào để tôi biết cái đúng là gì? Nếu bạn có một cách tốt hơn để làm điều này, xin vui lòng đề nghị đó là tốt.

EDIT

Xin lỗi, nhưng tôi quên đề cập đến một phần quan trọng của thông tin. Phương thức Draw cho mỗi lớp ở trên có một đối số khác nhau. Ví dụ: Ví dụ: Draw đối với Image<Bgr, Byte> có đối số kiểu BgrDraw cho số Image<Hsv, Byte> thay thế đối số kiểu Hsv.

+0

Bạn có quyền truy cập vào mã IImage và hình ảnh không? –

+0

EmguCV là một dự án mã nguồn mở, mặc dù tôi thực sự thích chỉ sử dụng các tệp nhị phân của họ :) – Aishwar

+0

Nó không giống giao diện/triển khai hình ảnh được thiết kế tốt. –

Trả lời

0

Làm thế nào về một cái gì đó như thế này:

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

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

Tôi nghĩ tốt hơn là nên triển khai một thay vì nhiều lần. –

+2

Đây chỉ là việc xin lỗi cho mã sloppy. Bây giờ cho mọi loại bạn sẽ phải thêm mã ở nhiều nơi. Nó có lẽ sẽ tốt hơn để ngoại suy logic này, và tất cả các logic cho các loại hình ảnh khác nhau, vào một số loại renderer hơn làm một cái gì đó như thế này. –

+0

Tôi đồng ý có những câu trả lời hay khác và điều này nói chung có thể dẫn đến mã rất cẩu thả. Nhưng trong trường hợp của tôi, tôi chỉ phải làm điều đó một lần và tôi không muốn chỉnh sửa các tập tin nguồn EmguCV. Tôi đã sử dụng điều này, vì vậy tôi sẽ đánh dấu điều này là được chấp nhận. – Aishwar

1

Nếu tôi hiểu bạn một cách chính xác - dụng cụ lớp hình vẽ phương pháp. Tôi không biết làm thế nào bạn sẽ sử dụng nó, nhưng bạn có thể làm theo cách này:

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

Vấn đề chính về trên là người gọi của phương pháp trên nên xác định T1 và T2 loại.

Nếu bạn không có quyền kiểm soát giao diện IImage và triển khai của nó thì tôi nghĩ bạn sẽ chọn từ hai giải pháp: chỉ định kiểu T1 và T2 hoặc có ifs/switch với tất cả triển khai IImage có thể.

Nếu bạn có quyền truy cập vào giao diện IImage và lớp Hình ảnh thì bạn nên thêm giao diện IImage chung và thêm phương thức Vẽ vào nó.

+0

theo cách này bạn cần các phương pháp khác nhau cho các loại chung khác nhau. – JohnIdol

+0

Tại sao? Bạn chỉ cần gọi phương thức trên với các tham số kiểu cần thiết. –

0

Nếu bạn chắc chắn rằng hình ảnh < T, U > rằng bạn sẽ có (không phân biệt các loại) sẽ có phương thức Draw, bạn có thể sử dụng phản xạ và hack xung quanh nó:

tôi sẽ làm nó như là một phương pháp mở rộng:

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

Một chút của một hack, nhưng sau đó một lần nữa, tôi sẽ nói rằng API không được thiết kế đúng cách. Nên có ít nhất là một số lớp học ngăn kéo hoặc một cái gì đó mà sẽ biết làm thế nào để hành động trên một hình ảnh.

+0

Điều này sẽ rất chậm. –

+0

Tối ưu hóa sớm nhiều? – BFree

+0

Không, phản xạ chậm và các giải pháp đề xuất không phải là cách tự nhiên về cách phản xạ nên được sử dụng. –

1

Bạn sẽ có giao diện dùng chung để thêm Draw().

3

Thêm IDrawableImage kế thừa từ IImage.

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

Sau đó, bạn chỉ có thể làm như sau:

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

Để phù hợp làm rõ của bạn ở trên:

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

sau đó nếu bạn biết loại:

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

nếu bạn không

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

Cách tốt nhất là tạo giao diện cho các loại vấn đề này. Kiểm tra mỗi lần thực hiện (như trong ví dụ của Adel) vi phạm nguyên tắc Mở/đóng (http://en.wikipedia.org/wiki/Open/closed_principle) và tạo ra sự kết hợp cao (http://en.wikipedia.org/wiki/Coupling_ % 28computer_science% 29). Với giao diện này, bạn có thể tạo một kiểu 'Image ' mới và sử dụng nó mà không thay đổi bất kỳ mã nào gọi phương thức 'Vẽ'. – Ronald

+0

Thats chính xác lý do tại sao tôi đề nghị phương pháp này, làm lớn nếu báo cáo có chút tôi ở phía sau nhiều hơn tôi có thể đếm trong những năm qua, đặc biệt là khi bạn bắt đầu làm điều này ở khắp mọi nơi. Đột nhiên bạn cần một bài viết wiki nội bộ về cách thêm một kiểu mới vào nó vì nó chạm vào rất nhiều mã. –

0

Câu hỏi của bạn thiếu thông tin quan trọng: mã bạn muốn viết.

Chúng tôi cần biết bạn định viết mã gọi phương thức Draw(...) như thế nào.

0

Hoặc bạn có thể sử dụng các phương pháp động và nắm bắt cơ hội của mình.

Các vấn đề liên quan