2011-11-13 24 views
9

Beynim jöle döndü, ya da bir aklı başında veya başka bir şey yaşadım. Ben görünen bir sınıf hiyerarşisi ile müdahalesi ediyorum böyle biraz:
enter image description hereOperatörler ve devralma

Benim Money sınıf şuna benzer:

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); 
    } 
} 

Benim Dolar operator * şöyle görünür:

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

Şimdi, bu test kodunu çalıştırırsam, bir yığın taşması (wahoo!)

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

Bunun, (Dolar * int) yinelemeli olarak tanımlanmadığı için kesin bir sonuç döndüren alt sınıf (Dolar) operator *'u tekrar tekrar çağırmasını bekledim. Bu işe yaramadığından, alternatif bir şey yapmam. Bu neden çalışmıyor? Bu davranışı elde etmenin doğru yolu ne olurdu?

+1

Yığın taşması olduğunda, yığını incelemelisiniz. Birbirini tekrar tekrar arayarak aynı işlevleri göreceksiniz. Bu, ne olduğunu ve neden olduğu hakkında çok şey söyleyecektir. – abelenky

+2

Özyinelemenin, Money.operator * ',' Dollar.operator * 'değil çağırdığınız için gerçekleştiğini unutmayın. Operatörler * aşırı yüklenmiş *, * geçersiz kılınmış *, ve çalıştırılan işlev, * çalışma zamanı * türleri değil, işlenenlerin * derleme zamanı * türleri tarafından belirlenir. "BeşDollar", "Para" türünde bir değişken olduğundan, "BeşDollar" * 2 "operatörün * Para" sürümünü çağırır (* çalışma zamanı * beşDollar’ın türü "Dolar'dır" olsa bile) – dlev

cevap

11

Sen

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

+1 teşekkürler, iyi yakalama –

4

sorun .Amount dışarı bırakmış görünüyor size geçersiz kılma türetilmiş sınıfları operatörler ve dynamic binding bekleyebilirsiniz bekliyoruz olmasıdır. Bu C# içinde çalışma şekli değil. Operatörler aşırı yüklenmiştir ve gerçek aşırı yük derleme zamanı seçilir. Bu aşağıdaki kod yinelemeli olduğu anlamına gelir ve kendisini aramalar:

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

aşırı yükleme operatör ve yazdırma metodu arasındaki farkı görmek bir başka örneği şudur: Üçüncü durumda

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 

, C# a ve b öğelerini tamsayılar yerine nesneler olarak kabul eder, böylece nesneler için kullanılan varsayılan == işlecini kullanır: referansları karşılaştırır (bu durumda kutulu tamsayıların referansları). Bu, işleçleri türetilmiş sınıflardaki yeniden tanımlamak istediğiniz bir sınıf hiyerarşisinde tanımlamayı zorlaştırabilir. C# (ve diğer birçok OOP dilinin) multiple dispatch desteğinden yoksun olduğundan, davranış her iki işlenenin birleşmesine bağlı olduğunda özellikle gariptir. Bunu ziyaretçi modelini kullanarak çözebilirsiniz, ancak bu durumda, her bir para birimi için alt sınıfları kullanmanın en iyi çözüm olduğunu düşünmeniz gerektiğini düşünüyorum.

+0

+1 Evet, bu gerçekten problem gibi görünüyor. Ben _did_ operatörleri geçersiz kıldım, burada bir şey öğrendim :) –