2011-11-13 8 views
9

Não của tôi đã chuyển sang dạng thạch, hoặc tôi đang có một trải nghiệm ngoài ý muốn hoặc thứ gì đó. Tôi đang mày mò với một hệ thống phân cấp lớp đó trông hơi như thế này:
enter image description hereCác nhà khai thác và thừa kế

lớp Money của tôi trông như thế này:

public abstract class Money 
{ 
    public int Amount { get; set; } 

    public static bool operator ==(Money leftSide, Money rightSide) 
    { 
     // Money can only be equal if it is in the same currency. 
     if (leftSide.GetType() != rightSide.GetType()) return false; 
     return leftSide.Amount == rightSide.Amount; 
    } 

    public static bool operator !=(Money leftSide, Money rightSide) 
    { 
     // If the currencies are different, the amounts are always considered unequal. 
     if (leftSide.GetType() != rightSide.GetType()) return true; 
     return leftSide.Amount != rightSide.Amount; 
    } 

    public static Money operator *(Money multiplicand, int multiplier) 
    { 
     var result = multiplicand * multiplier; 
     return result; 
    } 

    public static Dollar Dollar(int amount) 
    { 
     return new Dollar(amount); 
    } 

    public static Franc Franc(int amount) 
    { 
     return new Franc(amount); 
    } 
} 

Dollar My operator * trông như thế này:

public static Dollar operator *(Dollar multiplicand, int multiplier) 
{ 
    var result = multiplicand.Amount * multiplier; 
    return new Dollar(result); 
} 

Bây giờ, nếu tôi chạy mã kiểm tra này, tôi sẽ nhận được tràn ngăn xếp (wahoo!)

{ 
    Money fiveDollars = Money.Dollar(5); 
    Money timesTwo = fiveDollars*2; 
} 

Tôi đã dự kiến ​​rằng điều này sẽ đệ quy gọi lớp con (Dollar) operator *, sẽ trả về kết quả xác định vì (Dollar * int) được xác định không đệ quy. Vì điều này không hiệu quả, cách khác là tôi đã làm điều gì đó ngu ngốc. Tại sao nó không hoạt động? Điều gì sẽ là đúng cách để có được hành vi này?

+1

Khi bạn bị tràn ngăn xếp, bạn nên kiểm tra ngăn xếp. Bạn sẽ thấy các chức năng tương tự gọi cho nhau nhiều lần. Điều đó một mình sẽ cho bạn biết rất nhiều về những gì đang xảy ra và tại sao. – abelenky

+2

Lưu ý rằng đệ quy xảy ra bởi vì bạn đang thực sự gọi 'Money.operator *', không phải 'Dollar.operator *'. Các toán tử * bị quá tải *, không * ghi đè *, và do đó hàm được gọi được xác định bởi các kiểu * thời gian biên dịch * của các toán hạng, không phải kiểu * thời gian chạy *. Vì 'nămDollars' là một biến kiểu' Money', 'nămDollars * 2' gọi' phiên bản 'tiền' của toán tử * '(mặc dù kiểu * thời gian chạy * của' nămDollars' là 'Dollar'.) – dlev

Trả lời

11

Bạn dường như đã bỏ qua .Amount

public static Money operator *(Money multiplicand, int multiplier) 
{ 
    var result = multiplicand.Amount * multiplier; 
    return result; 
} 
+0

1 cảm ơn, nắm bắt tốt –

4

Vấn đề là bạn hy vọng rằng bạn có thể ghi đè nhà khai thác trong các lớp thừa kế và mong muốn dynamic binding. Đây không phải là cách nó hoạt động trong C#. Các nhà khai thác bị quá tải và quá tải thực tế được chọn thời gian biên dịch. Điều này có nghĩa rằng đoạn mã sau đệ quy và tự gọi mình:

public static Money operator *(Money multiplicand, int multiplier) 
{ 
    var result = multiplicand * multiplier; 
    return result; 
} 

Một ví dụ khác, nơi bạn có thể thấy sự khác biệt giữa các nhà khai thác quá tải và phương pháp quan trọng nhất là điều này:

int a = 5; 
int b = 5; 

Console.WriteLine(a == b); // true 
Console.WriteLine(a.Equals(b)); // true 
Console.WriteLine((object)a == (object)b); // false 
Console.WriteLine(((object)a).Equals((object)b)); // true 

Trong trường hợp thứ ba, C# xử lý ab làm đối tượng thay vì số nguyên, do đó, nó sử dụng toán tử mặc định == được sử dụng cho đối tượng: so sánh tham chiếu (trong trường hợp này tham chiếu đến số nguyên được đóng hộp).

Điều này có thể làm cho nó khó xử khi xác định toán tử trên phân cấp lớp nơi bạn muốn xác định lại toán tử trong các lớp dẫn xuất. Nó đặc biệt khó xử khi hành vi phụ thuộc vào sự kết hợp của cả hai toán hạng, vì C# (và hầu hết các ngôn ngữ OOP khác) thiếu hỗ trợ cho multiple dispatch. Bạn có thể giải quyết điều này bằng cách sử dụng mẫu khách truy cập, nhưng tôi nghĩ trong trường hợp này, bạn nên xem xét lại nếu sử dụng các lớp con cho mỗi loại tiền tệ là giải pháp tốt nhất.

+0

+1 Vâng, điều đó thực sự có vẻ là vấn đề. Tôi _did_ nghĩ rằng các toán tử bị ghi đè, tôi đã học được điều gì đó ở đây :) –