2009-12-11 60 views
9
public void DoSomething(params object[] args) 
{ 
    // ... 
} 

Vấn đề với chữ ký ở trên là mọi loại giá trị sẽ được chuyển cho phương thức đó sẽ được đóng hộp hoàn toàn và đây là vấn đề hiệu suất nghiêm trọng đối với tôi.Số lượng đối số thay đổi mà không có quyền sử dụng các loại giá trị?

Có cách nào để từ chối phương thức chấp nhận số lượng đối số thay đổi mà không có quyền sử dụng các loại giá trị không?

Cảm ơn.

Trả lời

12

Bạn có thể sử dụng Generics:

public void DoSomething<T>(params T[] args) 
{ 
} 

Tuy nhiên, điều này chỉ sẽ cho phép một loại duy nhất của ValueType để được xác định. Nếu bạn cần trộn hoặc kết hợp các kiểu giá trị, bạn sẽ phải cho phép boxing xảy ra, như bạn đang làm bây giờ, hoặc cung cấp quá tải cụ thể cho các số tham số khác nhau.


Chỉnh sửa: Nếu bạn cần nhiều loại thông số, bạn có thể sử dụng quá tải để thực hiện việc này ở một mức độ nào đó.

public void DoSomething<T,U>(T arg1, params U[] args) {} 
public void DoSomething<T,U>(T arg1, T arg2, params U[] args) {} 

Thật không may, điều này đòi hỏi nhiều quá tải tồn tại đối với các loại của bạn.

Ngoài ra, bạn có thể vượt qua trong mảng trực tiếp:

public void DoSomething<T,U>(T[] args1, U[] args2) {} 

Bạn mất cú pháp biên dịch tốt đẹp, nhưng sau đó bạn có thể có bất kỳ số lượng hai tham số rồi.

+0

có nhưng điều này giới hạn loại toàn bộ danh sách đối số thành một loại ... – DxCK

+0

Bạn có thể kết hợp và khớp với quá tải ... –

+0

Tôi đã chỉnh sửa để thêm thông tin tại đây ... –

3

Hiện tại, không, và tôi chưa thấy bất kỳ điều gì giải quyết vấn đề trong thông tin .NET 4 đã được phát hành.

Nếu đó là vấn đề hiệu suất rất lớn đối với bạn, bạn có thể xem xét một số tình trạng quá tải của danh sách tham số thường thấy.

Tôi tự hỏi, mặc dù: có phải là thực sự là sự cố hiệu suất hay bạn đang tối ưu hóa sớm?

-1

Trong C# 4.0 bạn có thể sử dụng các tham số có tên (và do đó tùy chọn)! Thông tin thêm về this blog post

+1

OMG ... Đó là chủ đề hoàn toàn khác. –

+0

Hmmm ...Tôi chưa chắc chắn chức năng cần thiết là gì nên có thể tôi đã sai và có lẽ tôi không phải. Cụm từ "chấp nhận số lượng đối số thay đổi mà không cần đánh giá các loại giá trị" mặc dù tôi tin rằng có thể được thỏa mãn bởi các tham số được đặt tên .... –

3

Giả sử mã bạn đang gọi phương thức này nhận biết các loại đối số. Nếu vậy, bạn có thể đóng gói chúng vào loại Tuple thích hợp từ .NET 4 và truyền thể hiện của nó (Tuple là kiểu tham chiếu) đến phương thức như đối tượng (vì không có cơ sở chung cho tất cả các Tuple).

Vấn đề chính ở đây là nó không phải là dễ dàng để xử lý các đối số bên trong phương pháp này mà không có boxing/unboxing, và có khả năng, thậm chí không có sự phản ánh. Cố gắng suy nghĩ những gì phải được thực hiện để trích xuất, giả sử, đối số thứ N mà không có quyền anh. Bạn sẽ kết thúc với sự hiểu biết bạn phải hoặc là đối phó với tra cứu từ điển (s) có (liên quan hoặc thường xuyên Dictionary<K,V> hoặc internal dictionaries được sử dụng bởi CLR), hoặc với boxing. Rõ ràng, tra cứu từ điển là tốn kém hơn nhiều.

Tôi viết bài này vì chúng tôi đã phát triển giải pháp cho vấn đề tương tự: chúng tôi phải có thể hoạt động với our own Tuples mà không cần quyền anh - chủ yếu là để so sánh và deserialize chúng (Tuple được sử dụng bởi cơ sở dữ liệu mà chúng tôi phát triển. của bất kỳ hoạt động cơ bản nào thực sự cần thiết trong trường hợp của chúng tôi).

Nhưng:

  • Chúng tôi kết thúc với giải pháp khá phức tạp. Hãy xem ví dụ: tại TupleComparer.
  • Ảnh hưởng của việc thiếu boxing thực sự không tốt như mong đợi: mỗi thao tác boxing/unboxing được thay thế bằng chỉ mục mảng đơn và vài cuộc gọi phương thức ảo, chi phí của cả hai cách gần giống nhau.

Lợi ích duy nhất của cách tiếp cận mà chúng tôi phát triển là chúng tôi không "tràn" Gen0 bởi rác thải, vì vậy các bộ sưu tập Gen0 hiếm khi xảy ra hơn nhiều. Vì chi phí thu thập Gen0 tỷ lệ thuận với không gian được phân bổ bởi các đối tượng "sống" và số đếm của chúng, điều này mang lại lợi thế đáng chú ý, nếu các phân bổ khác xen kẽ với (hoặc đơn giản là xảy ra trong) thực hiện thuật toán chúng tôi cố gắng tối ưu hóa theo cách này.

Kết quả: sau khi tối ưu hóa này, các thử nghiệm tổng hợp của chúng tôi được hiển thị từ 0% đến 200-300% tăng hiệu suất; mặt khác, kiểm tra hiệu suất đơn giản của bản thân cơ sở dữ liệu đã cho thấy sự cải thiện ít ấn tượng hơn nhiều (khoảng 5-10%). Rất nhiều thời gian đã bị lãng phí ở các lớp trên (cũng có một ORM khá phức tạp), nhưng ... Rất có thể đó là những gì bạn sẽ thực sự thấy sau khi thực hiện các công cụ tương tự.

Tóm lại, tôi khuyên bạn nên tập trung vào một thứ khác. Nếu nó sẽ được hoàn toàn rõ ràng đây là một vấn đề hiệu suất lớn trong ứng dụng của bạn, và không có cách nào khác tốt để giải quyết nó, tốt, đi trước ... Nếu không bạn chỉ đơn giản là thép từ khách hàng của bạn hoặc của riêng bạn bằng cách làm sớm tối ưu hóa.

0

Để thực hiện hoàn toàn chung, cách giải quyết chung là sử dụng mẫu thông thạo. Một cái gì đó như thế này:

public class ClassThatDoes 
{ 
    public ClassThatDoes DoSomething<T>(T arg) where T : struct 
    { 
     // process 

     return this; 
    } 
} 

Bây giờ bạn gọi:

classThatDoes.DoSomething(1).DoSomething(1m).DoSomething(DateTime.Now)//and so on 

Tuy nhiên điều đó không làm việc với các lớp tĩnh (phương pháp khuyến nông là ok vì bạn có thể quay trở lại this).

Câu hỏi của bạn về cơ bản giống như sau: Can I have a variable number of generic parameters? được hỏi theo cách khác.

Hoặc chấp nhận một loạt các mục có params keyword:

public ClassThatDoes DoSomething<T>(params T[] arg) where T : struct 
{ 
    // process 

    return this; 
} 

và gọi:

classThatDoes.DoSomething(1, 2, 3) 
      .DoSomething(1m, 2m, 3m) 
      .DoSomething(DateTime.Now) //etc 

Cho dù các mảng tạo overhead ít hơn đấm bốc trên đầu là một cái gì đó bạn sẽ phải tự quyết định.

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