2010-02-09 36 views
5

Ok, tôi đang cố gắng để làm như sau:Phương pháp quá tải: phễu cuộc gọi đến lớp có nguồn gốc lý luận quá tải

 protected bool ValidAdvert(Base item) 
     { 
      throw ThisIsAnAbstractClassException(); 
     } 

     protected bool ValidAdvert(Derived1 item) 
     { 
      return ADerived1SpecificPredicate; 
     } 

     protected bool ValidAdvert(Derived2 item) 
     { 
      return ADerived2SpecificPredicate; 
     }

Và có các phiên bản lớp Derived của phương pháp này được gọi là, khi một lớp cơ sở sẽ được chuyển cho phương pháp. Lớp cơ sở là trừu tượng, do đó, điều này có nên, theo lý thuyết, có thể?

Trước khi ai đó nói điều gì đó về quá tải phương thức trên lớp, logic bên trong các phương thức dựa trên một số lượng lớn các điều kiện khác nhau, không có điều kiện nào liên quan đến chúng. như tình trạng đăng nhập, vv)

Trả lời

6

Nếu bạn tìm thấy công văn kép quá xâm nhập, bạn có thể gọi phương thức bằng cách phản ánh và giải quyết tình trạng quá tải thích hợp động.

protected bool ValidAdvert(Base item) 
{ 
    if (item.GetType() == typeof(Base)) 
     throw new ThisIsAnAbstractClassException(); 

    Type type = typeof(CurrentClass); 

    MethodInfo method = type.GetMethod("ValidAdvert", 
             BindingFlags.Instance | BindingFlags.NonPublic, 
             null, 
             new Type[] { item.GetType() }, 
             null); 
    return (bool)method.Invoke(this, new object[] { item }); 
} 

protected bool ValidAdvert(Derived1 item) 
{ 
    return ADerived1SpecificPredicate; 
} 

protected bool ValidAdvert(Derived2 item) 
{ 
    return ADerived2SpecificPredicate; 
} 

mô hình này được gọi là MultipleDispatch, trong khi gọi một phương pháp mà theo phản ánh là chậm hơn so với gọi phương pháp trực tiếp (nó sẽ không phải là một chi phí nếu phương pháp này được gọi là ít hơn vài trăm lần mỗi giây), nó có lợi ích của việc không yêu cầu sửa đổi thứ bậc lớp như trong mô hình Công văn kép.

này sẽ dễ dàng hơn khi C# 4.0 đi ra với từ khóa động:

protected bool ValidAdvert(Base item) 
{ 
    if (item.GetType() == typeof(Base)) 
     throw new ThisIsAnAbstractClassException(); 

    dynamic dynamicThis = this; 

    return (bool)dynamicThis.ValidAdvert(item as dynamic); 
} 
+0

Cũng thông minh, và tránh rối tung với các lớp học có nguồn gốc khác nhau (tôi muốn có chỉ có 2!). –

+0

khá ghi chú: bạn cần phải cast để bool trên sự trở lại, và method.Invoke mất một [] của các đối tượng, và do đó craps ra nếu bạn cố gắng và vượt qua chỉ 1 :) Cảm ơn mặc dù! –

+0

@Ed - Tôi nghĩ rằng việc giữ vị từ với lớp dẫn xuất thực sự là phương thức ưa thích. Việc lưu trữ logic lớp cụ thể có nguồn gốc trong một lớp cơ sở tạo ra một sự ghép nối ngược giữa hai lớp. Tôi không thấy đây là một điều tốt. Lớp cơ sở không cần biết bất cứ điều gì về các lớp dẫn xuất của nó. – tvanfosson

5

một nơi lý tưởng để sử dụng double dispatch:

class Base 
{ 
    public abstract bool IsValid(IAdvertValidator validator); 
} 

class Derived1 : Base 
{ 
    public bool IsValid(IAdvertValidator validator) 
    { 
     return validator.ValidAdvert(this); 
    } 
} 

class Derived2 : Base 
{ 
    public bool IsValid(IAdvertValidator validator) 
    { 
     return validator.ValidAdvert(this); 
    } 
} 

interface IAdvertValidator 
{ 
    bool ValidAdvert(Derived1 d1); 
    bool ValidAdvert(Derived2 d2); 
} 
+0

Clever, tôi thích nó. –

+0

Sử dụng hợp lý mẫu. Một giải pháp thay thế là để trưng ra các phương thức xác nhận hợp lệ từ trình xác nhận hợp lệ và sử dụng chúng bên trong việc thực hiện IsValid, giữ luồng kiểm soát xác thực thực tế trong lớp. – tvanfosson

0

tôi không chắc chắn chính xác như bạn bao giờ sẽ có một thể hiện của các lớp cơ sở đó không phải là thực sự là một ví dụ của một lớp dẫn xuất. Vì lớp cơ sở là trừu tượng, nó không thể được khởi tạo. Tôi cho rằng nó sẽ phù hợp với bất kỳ lớp học có nguồn gốc mà không có một chữ ký cụ thể, nhưng điều đó dường như không phải là những gì bạn đang đi.

+0

Vâng, nó luôn luôn là một trong các lớp dẫn xuất, tuy nhiên, nó cũng về mặt kỹ thuật là lớp cơ sở, có nghĩa là phương thức lớp cơ sở được gọi khi tôi làm (Ví dụ: ) i.Where (ValidateAdvert). –

+0

Ah - Tôi đã đọc mẫu mã của bạn, không phải câu hỏi của bạn. Bạn không thực sự muốn nó ném một ngoại lệ, bạn muốn nó gọi một trong những phương pháp khác để thay thế. Trong trường hợp đó tôi sẽ đi với gợi ý của @ Anton, hoặc một cái gì đó tương tự. Lưu ý rằng bạn có thể cung cấp trình xác nhận hợp lệ trong một hàm tạo để bạn không cần chuyển nó thành một đối số. Tôi cũng đã sử dụng một lớp xác nhận hợp lệ để xác thực các thuộc tính đơn giản, loại bỏ sự cần thiết phải giữ một tham chiếu đến nó. Bạn cần phải cẩn thận với những điều này, tuy nhiên, vì chúng có thể làm cho thử nghiệm khó hơn nếu bạn không cẩn thận. – tvanfosson

+0

Trình xác nhận là rất nhiều lớp trang và trạng thái cụ thể, và vì vậy sẽ không hoạt động độc đáo như tĩnh, tuy nhiên tôi nghĩ nó khá độc đáo trong phương pháp phản chiếu, thật đáng tiếc điều này không được hỗ trợ theo mặc định Tuy nhiên! –

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