2012-02-29 20 views
6

câu hỏi liên quan: Accessing a Class property without using dot operatorĐúc Lớp tôi để Int64, đôi vv

tôi đã tạo ra một lớp được gọi là MyDouble trông như thế này

class MyDouble 
{ 
    double value; 
    //overloaded operators and methods 
} 

tôi có thể làm tất cả các loại hoạt động trên MyDouble. Ví dụ:

MyDouble a = 5.0; 
a += 3.0; 
...etc 

Tuy nhiên, đây vẫn ném một lỗi

MyDouble a = 5.0; 
long b = (Int64)a; //error 
long b = (int64)a.value; //works 

Làm thế nào tôi có thể định nghĩa nó như vậy mà một hoạt động như (Int64)a tự động chuyển đổi để (Int64)a.value? Tôi không muốn người dùng phải lo lắng về sự tồn tại của thuộc tính value.

+0

Tại sao bạn sử dụng cả 'long' và' Int64'? Một là một aloas cho người khác và tôi nghĩ cách thành ngữ hơn là sử dụng các bí danh nếu chúng tồn tại thay vì các tên kiểu. – Joey

Trả lời

9

Để chuyển đổi này hoạt động, bạn cần có explicit conversion đến Int64.

này sẽ như thế nào:

class MyDouble 
{ 
    double value; 

    public static explicit operator Int64(MyDouble value) 
    { 
     return (Int64)value.value; 
    } 
} 
+0

Hoàn hảo, cảm ơn bạn. – xbonez

+0

Tại sao phải rõ ràng? Một chuyển đổi ngầm cũng hoạt động tốt và dàn diễn viên trở thành tùy chọn. – Jay

+0

@Jay Bạn * có thể * thực hiện thao tác ngầm, nhưng OP cho thấy bao gồm toán tử chuyển đổi. Cá nhân, tôi có xu hướng cố gắng tránh chuyển đổi tiềm ẩn, trừ khi họ thực hiện rất nhiều ý nghĩa (ngầm chuyển đổi từ đôi sang dài có vẻ như một ý tưởng tồi, mặc dù). –

1

Có một chuyển đổi rõ ràng từ hai đến Int64, nhưng không phải từ lớp học của bạn để Int64. tất cả những gì bạn cần làm là xác định một. Hoặc, nếu bạn có một chuyển đổi từ lớp học của bạn để tăng gấp đôi, mà tôi cho rằng bạn làm, bạn có thể làm điều này:

long x = (long) (double) a;

Tuy nhiên, điều đó cồng kềnh; Tôi muốn xác định toán tử chuyển đổi rõ ràng.

Chuyển đổi phải rõ ràng, không ngầm, trừ khi bạn có lý do chính đáng để làm rõ.

Chuyển đổi được xác định bằng ngôn ngữ từ kép thành dài rõ ràng do chuyển đổi có thể gây mất thông tin. Bạn có thể mất thông tin với chuyển đổi này vì có một số đôi, như 0,5, không chuyển đổi chính xác thành dài. Đây được gọi là thu hẹp chuyển đổi.

Với chuyển đổi được xác định bằng ngôn ngữ, thu hẹp chuyển đổi rõ ràng. Nếu chúng được ngầm định, các lập trình viên có thể vô tình mất thông tin bằng cách gán một giá trị của một kiểu cho một biến kiểu khác. Xác định chuyển đổi này là ngầm định vi phạm nguyên tắc hoàn toàn hợp lý, vì vậy sẽ phải có một số trường hợp hấp dẫn để làm như vậy.

Dưới đây là ví dụ hiển thị giá trị của nguyên tắc này. Nếu thu hẹp chuyển đổi được ngầm định, nó sẽ làm cho mã dễ vỡ hơn. Giả sử rằng chuyển đổi kép thành nội dung ẩn:

class Family 
{ 
    ICollection<Person> Children { get; set; } 
} 

int GetAverageNumberOfChildren(IEnumerable<Family> families) 
{ 
    return families.Sum(f => f.Children.Count)/families.Count(); 
} 

void SomeMethod(IEnumerable<Family> families) 
{ 
    int averageNumberOfChildren = GetAverageNumberOfChildren(families); 
    //... 
} 

Rất tiếc! Chúng tôi có một lỗi! GetAverageNumberOfChildren sẽ trả về gấp đôi! Hãy sửa nó!

double GetAverageNumberOfChildren(IEnumerable<Family> families) 
{ 
    return families.Average(f => f.Children.Count); 
} 

Whew, mọi thứ biên dịch và chạy! Chắc chắn vui vì chúng tôi đã bắt được lỗi đó!

Nhưng thật đáng buồn là không. Chúng tôi vẫn có lỗi!SomeMethod chuyển đổi hoàn toàn số double thành int, do đó, giá trị mong đợi có thể là 2.4, giá trị thực tế là 2.

Vì chuyển đổi hai thành một là rõ ràng, trình biên dịch lưu chúng ta khỏi chính chúng ta. Sau khi chúng tôi sửa lỗi GetAverageNumberOfChildren, chương trình không đúng sẽ không biên dịch.

Bây giờ, nếu lớp học MyDouble của bạn có một số xác thực đã hạn chế nó thành giá trị nguyên với phạm vi bằng hoặc nhỏ hơn phạm vi long, thì bạn sẽ an toàn để chuyển đổi ẩn. Nhưng trong trường hợp đó, tất nhiên, bạn nên sử dụng long, không phải double.

1

Một chuyển đổi tiềm ẩn sẽ hoạt động cũng như chuyển đổi rõ ràng.

public static implicit operator long(MyDouble m) 
{ 
    return (long) m.value; 
} 

Với điều này trong nơi bạn có thể làm:

long b = (Int64) a; 

hoặc chỉ

long b = a; 

Đây chỉ là để minh họa rằng việc chuyển đổi không cần phải được rõ ràng. Tuy nhiên, như đã lưu ý, nó nên rõ ràng vì có khả năng mất dữ liệu.

+0

Điều này đúng, nhưng nguy hiểm. Xem câu trả lời đã chỉnh sửa của tôi để được giải thích. – phoog

+0

@phoog Tôi hiểu. Tôi chỉ đang gặp vấn đề với ngôn ngữ "bạn * cần * một chuyển đổi rõ ràng". – Jay

+0

Đủ công bằng; Tôi chỉ nghĩ rằng nếu chúng ta đang thảo luận về sự tồn tại của các chuyển đổi tiềm ẩn, sẽ là khôn ngoan để thảo luận về lý do làm cho việc thu hẹp chuyển đổi rõ ràng. Nếu không, một người nào đó có thể bị cám dỗ thực hiện chuyển đổi phải rõ ràng là chuyển đổi tiềm ẩn "bởi vì nó dễ dàng hơn" hoặc "vì nó làm cho mã của tôi sạch hơn", mà không xem xét khả năng viết các chương trình lỗi. – phoog

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