2010-11-20 33 views
5

Tôi đã gặp một số mã vào ngày khác và tôi tự hỏi đó có phải là cách tốt nhất để làm điều đó hay không. Chúng ta có một phương thức lấy một chuỗi từ một số dữ liệu biểu mẫu web để thực hiện một thứ gì đó cho một đối tượng dựa trên chuỗi được truyền vào. Hiện tại, nó sử dụng sự phản chiếu để tìm ra hành động nào cần thực hiện, nhưng tôi tự hỏi liệu một câu lệnh switch có tốt hơn không .Nhà máy Phương pháp - trường hợp và phản ánh

Ví dụ:

Edit: Tôi đã thêm một lựa chọn thứ ba cho các đại biểu như ghi nhận của Lucerno

public class ObjectManipulator 
{ 
    private void DoX(object o) { } 
    private void DoY(object o) { } 
    private void DoZ(object o) { } 

    public void DoAction(string action, object o) 
    { 
     switch (action) 
     { 
      case "DoX": 
       DoX(o); 
       break; 
      case "DoY": 
       DoY(o); 
       break; 
      case "DoZ": 
       DoZ(o); 
       break; 
      default: 
       throw new Exception(string.Format(
        "Cannot locate action:{0}", action)); 
     } 
    } 

    public void DoActionViaReflection(string action, object o) 
    { 
     MethodInfo method = typeof(ObjectManipulator). 
      GetMethod(action, new Type[] { typeof(object) }); 
     if (method == null) 
     { 
      throw new Exception(string.Format(
       "Cannot locate action:{0}", action)); 
     } 
     else 
     { 
      method.Invoke(this, new object[] { o }); 
     } 
    } 
    private Dictionary<string, Action<object>> _methods; 
    public ObjectManipulator() 
    { 
     _methods = new Dictionary<string, Action<object>>() 
     { 
      {"DoX", o => DoX(o)}, 
      {"DoY", o => DoY(o)}, 
      {"DoZ", o => DoZ(o)} 
     }; 
    } 
    public void DoActionViaDelegates(string action, object o) 
    { 
     if (!_methods.ContainsKey(action)) 
     { 
      throw new Exception(string.Format(
       "Cannot locate action:{0}", action)); 
     } 
     else 
     { 
      _methods[action](o); 
     } 
    } 

} 

Ví dụ đầu tiên sử dụng công tắc và như bạn có thể nhìn thấy có thể nhận được rất tiết. Thứ hai là ngắn hơn nhiều, nhưng sử dụng sự phản ánh, mà tôi biết một số người tránh như bệnh dịch hạch.

Một phương pháp có thực hiện tốt hơn đáng kể so với phương pháp kia không?

Thay đổi hiệu suất sẽ có nếu có 100 hành động khác nhau thay vì chỉ 3?

Bạn thích xem mã nào trong mã nếu bạn đang đọc?

+0

Đó là một câu hỏi khá nhiều về phong cách lập trình mệnh lệnh và bắt buộc. Kirk dường như thích cách bắt buộc, trong khi tôi thích cái thứ hai, như bạn có thể thấy từ câu trả lời của tôi. Không phải là "đúng" hoặc "sai", chỉ để làm rõ điều này. – Lucero

Trả lời

3

Trường hợp đầu tiên sẽ hầu như luôn luôn nhanh hơn. Tuy nhiên, hiệu suất của nó xuất phát từ thực tế là nó có thể bị ràng buộc sớm trong thời gian biên dịch, nhưng đó là nhược điểm lớn nhất của nó: cách tiếp cận này không thể, ví dụ, xử lý các assembly được nạp động, và nó dễ bị lỗi hơn vì nó bắt buộc và không khai báo. (Việc quên một hành động mới được thực hiện chẳng hạn là một điều có thể xảy ra nhanh chóng.)

Cách tiếp cận thông thường của tôi là sử dụng sự phản chiếu để thực hiện các mẫu như vậy trong thời gian khám phá. Điều này giúp bạn có được sự linh hoạt của phương pháp phản chiếu với hiệu suất rất gần với phương pháp tiếp cận sớm.

  • Giai đoạn khám phá: sử dụng phản ánh để tìm các thành viên (sử dụng thuộc tính, giao diện, chữ ký và/hoặc quy ước mã hóa). Trong trường hợp của bạn, bạn luôn có cùng chữ ký, do đó, người được ủy quyền sử dụng sẽ là Action<object>. Thêm các thành viên đó vào một phiên bản Dictionary<string, Action<object>>, tạo đại biểu từ MethodInfo bằng cách sử dụng CreateDelegate().

  • giai đoạn Invocation: có được các đại biểu thông qua chủ chốt của nó và gọi nó, mà là rất đơn giản (ở đây giả sử từ điển được gọi là methods): methods[action](o)

2

Hiệu suất không nên quan tâm của bạn, trừ khi bạn cấu nó và nó là một nút cổ chai. Quan trọng hơn, IMO, là bạn bị mất an toàn và phân tích kiểu tĩnh trong phiên bản phản chiếu. Không có cách nào để biên dịch thời gian để kiểm tra xem các phương thức hành động đó có được gọi là DoX, DOY, v.v. Điều này có thể hoặc có thể không phải là một vấn đề cho bạn, nhưng đó sẽ là mối quan tâm lớn nhất của tôi.

Ngoài ra, số lượng hành động hoàn toàn không liên quan đến hiệu suất của phiên bản phản chiếu. GetMethod không làm chậm khi bạn có nhiều thành viên trong lớp học của bạn.

+0

Gọi động trên một 'MethodInfo' là chậm, vì vậy đó sẽ là hit hiệu suất lớn nhất. – Lucero

+0

@Lucero, chắc chắn, nó chậm hơn. Câu hỏi đặt ra là liệu nó có quan trọng không. Theo kinh nghiệm của tôi, nó hiếm khi xảy ra. –

2

cách sử dụng đại biểu?bạn có thể sử dụng một cái gì đó như thế:

var Actions = new Dictionary<String, Action<object>>(); 
Actions["DoX"] = x => DoX(x); 
Actions["DoY"] = x => DoY(x); 
Actions["DoZ"] = x => DoZ(x); 

và sau

public void DoAction(string action, object o) 
{ 
    Actions[action](o); 
} 

tôi đoán rằng thực hiện tốt hơn, nếu bạn có nhiều trường hợp, vì từ điển có một tra cứu băm.

loại phản ánh bạn sử dụng có thể tạo ra các vấn đề an ninh, nếu người sử dụng có thể đưa ra trong một tên hàm

+0

Tôi nghi ngờ rằng điều này sẽ biên dịch, vì thực tế là 'DoX',' DoY' và 'DoZ' không hoạt động, nhưng lambda mong đợi một giá trị trả về. – Lucero

+0

ok sửa chữa nó, "hành động" là đúng loại cho một đại biểu mà không có bất kỳ giá trị trả lại – user287107

2

Bạn có thể sửa @ câu trả lời user287107 của thusly:

var Actions = new Dictionary<String, Action<object>>(); 
Actions["DoX"] = DoX; 
Actions["DoY"] = DoY; 
Actions["DoZ"] = DoZ; 

này có hiệu lực thực hiện việc khám phá giai đoạn của câu trả lời của @ Lucero rõ ràng, có thể hữu ích nếu các tên không phải lúc nào cũng khớp.

Xác định tập hợp các hành động trong enum cũng sẽ tốt đẹp nếu có thể - điều này sẽ nhanh hơn một chút vì bạn không cần băm chuỗi. Nó cũng sẽ cho phép bạn viết một bài kiểm tra đơn vị để đảm bảo rằng bạn đã không bỏ lỡ bất kỳ giá trị tiềm năng nào.

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