2010-09-28 33 views

Trả lời

9

Tiện lợi?

Ít hoặc nhiều, có. Hãy xem xét trường hợp khi bạn có đối tượng giống như số (ví dụ: Complex) mà bạn tính toán. Rõ ràng, viết mã như:

Complex result = c1 * new Complex(2) + new Complex(32); 

rất khó đọc và khó đọc. Chuyển đổi ngầm định giúp đỡ ở đây (một thay thế sẽ là quá tải của toán tử trong ví dụ này, nhưng điều đó sẽ dẫn đến nhiều sự quá tải tương tự).

Có hướng dẫn về điều này không?

Cung cấp ít chuyển đổi tiềm ẩn nhất có thể, vì chúng có thể ẩn sự cố. Chuyển đổi ngầm định làm giảm bớt sự chứng kiến ​​bằng cùng một số tiền mà chúng làm tăng sự tẻ nhạt. Đôi khi điều này là tốt, nhưng đôi khi không.

tôi thấy nó tốt nhất để hạn chế chuyển đổi ngầm để rất loại tương tự, chẳng hạn như các đối tượng số giống như trong ví dụ của tôi ở trên: một int về bản chất là-một Complex (từ quan điểm toán học, thậm chí nếu nó không được mô phỏng qua thừa kế), do đó một chuyển đổi tiềm ẩn có ý nghĩa.

Trong VB, chuyển đổi tiềm ẩn được gọi là “Widening” (ngược với Narrowing, là explicit) và điều này mô tả tốt: không có thông tin nào bị mất trong quá trình chuyển đổi. Hơn nữa, một toán tử về cơ bản là một hàm xây dựng, và có một số lợi thế thông thường của hàm xây dựng trên một hàm tạo: cụ thể là nó có thể sử dụng lại các giá trị được lưu trong bộ nhớ đệm thay vì luôn tạo các phiên bản mới.

Hãy xem xét ví dụ Complex của tôi. Chúng tôi có thể muốn lưu các giá trị bộ nhớ cache cho các số phức thường được sử dụng:

Class Complex { 
    // Rest of implementation. 

    private static Complex[] cache = new[] { 
     new Complex(-1), new Complex(0), new Complex(1) }; 

    public implicit operator Complex(int value) { 
     if (value >= -1 && value <= 1) 
      return cache[value]; 
     else 
      return new Complex(value); 
    } 
} 

Tất nhiên, việc tối ưu hóa vi mô này có hiệu quả hay không là một câu hỏi khác.

+0

Cảm ơn, bạn sẽ làm thế nào để quá tải nhà điều hành có thể giúp loại phức hợp? Bạn cần chỉnh sửa kiểu int, đúng không? –

+0

@Janan: Không, vì bạn có thể triển khai toán tử theo cả hai hướng: * từ * loại tùy chỉnh của bạn và * thành * loại tùy chỉnh của bạn. Trong ví dụ của tôi, chỉ đơn giản là có 'Complex' thực hiện một toán tử' implicit operator Complex (int value) '. –

+0

Cảm ơn tôi nhận được nó ngay bây giờ. –

3

Việc sử dụng chuyển đổi tiềm ẩn/rõ ràng là vấn đề tiện lợi và một trong nhiều nguyên tắc lập trình đề nghị bạn tránh ưu tiên các phương pháp rõ ràng ConvertToXXX.

Một trong những vấn đề là tha sử dụng các chuyển đổi ngầm định/rõ ràng hơn nữa làm quá tải các chức năng của toán tử đúc.Nó cung cấp cho nó trở thành mục đích kép của

  • Xem cùng một đối tượng thông qua một loại/giao diện khác nhau trong hệ thống phân cấp của đối tượng
  • coverting đối tượng cho một loại mới hoàn toàn

Đáng tiếc là C# đã thực hiện sau này ở các khu vực khác (với nguyên thủy và đấm bốc).

1

Cá nhân, tôi sử dụng chuyển đổi khi tôi biết rằng RHS có thể được chuyển đổi thành một thành viên tĩnh của một lớp (như nói color = "red" để ngụ ý color = Colors.Red)

tôi sử dụng các nhà điều hành mới khi tôi có ý định thực sự tạo ra một ví dụ mới.

2

Nếu hai lớp phải chuyển đổi với nhau, nhưng chúng không chia sẻ giao diện của lớp cơ sở cho phép hành vi này tự động, bạn sẽ sử dụng chuyển đổi. Chuyển đổi ngầm định nên không bao giờ có khả năng mất dữ liệu; chúng thường được coi là chuyển đổi "mở rộng". Ví dụ: chuyển đổi một số int thành một số long là một chuyển đổi mở rộng và không có vấn đề cố hữu trong chuyển đổi đang ẩn. Chuyển đổi rõ ràng có thể liên quan đến khả năng mất dữ liệu; a long có thể hoặc không thể chuyển đổi thành int, tùy thuộc vào giá trị của nó.

Một mẹo mà tôi đã sử dụng với chuyển đổi tiềm ẩn là chuyển đổi các lớp trong các không gian tên khác nhau khi tôi không có tùy chọn hợp lý khác. Ví dụ, một dịch vụ WCF trả về một đối tượng AuthenticationToken mà tôi cần phải chuyển đến một dịch vụ WCF trong một không gian tên khác. Cả hai đều có đối tượng AuthenticationToken này, và chuyển đổi liên tục sẽ là một cơn đau. Giải pháp của tôi liên quan đến việc sử dụng public static implicit operator trong một lớp học một phần để thêm chức năng chuyển đổi theo từng cách.

+0

Khái niệm rằng "chuyển đổi tiềm ẩn không gây ra mất dữ liệu" ngôn ngữ là phổ biến, nhưng tôi nghĩ rằng một khái niệm tốt hơn sẽ là "* chuyến đi khứ hồi * chuyển đổi tiềm ẩn không nên gây mất dữ liệu". Nếu 'SimpleType' đại diện cho một' ComplicatedType' trong đó các thuộc tính "complex" khớp với giá trị mặc định, chỉ nên cho phép mở rộng chuyển đổi từ 'SimpleType' thành' ComplicatedType', nhưng nếu nó đại diện cho một 'ComplicatedType' , chuyển đổi tiềm ẩn, nếu có, chỉ được phép theo cách khác. – supercat

5

Một trong những lý do đằng sau việc sử dụng chuyển đổi ngầm với các loại đơn giản như XName, tôi tin rằng, tiện lợi trong các phương thức gọi điện.

Ví dụ, bạn có thể viết

var info = root.Elements ("user").Element ("info").Value; 

Sự giản dị của giải nén dữ liệu là những gì LINQ là tất cả về, và nếu chúng ta phải viết

var info = root.Elements (new XName ("user")).Element (new XName ("info")).Value; 

ngay cả đối với các truy vấn đơn giản nhất, LINQ sẽ được hoàn toàn đáng giá cho những người phức tạp?

Một vấn đề quan trọng khác ở đây là các tệp được tạo thành atomized. Xem MSDN:

Đối tượng XName được đảm bảo là đã được phun ra; nghĩa là, nếu hai đối tượng XName có chính xác cùng một không gian tên và chính xác cùng tên địa phương, chúng sẽ chia sẻ cùng một trường hợp. Các nhà khai thác bình đẳng và so sánh cũng được cung cấp một cách rõ ràng cho mục đích này.

Trong số các lợi ích khác, tính năng này cho phép thực hiện truy vấn nhanh hơn. Khi lọc tên của các phần tử hoặc thuộc tính, các so sánh được thể hiện trong các vị từ sử dụng so sánh nhận dạng, không so sánh giá trị. Nhanh hơn nhiều để xác định rằng hai tham chiếu thực sự tham chiếu đến cùng một đối tượng hơn là so sánh hai chuỗi.

Bạn không thể cung cấp sương trong constructor, nhưng xác định một chuyển đổi cho phép bạn chọn đối tượng tương ứng từ hồ bơi và gửi lại như thể nó là một trường hợp mới.

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