2013-03-15 20 views
7

AKTUALIZACJA: Znalazłem odpowiedź, którą opublikuję za kilka dni, jeśli nikt inny tego nie zrobi.Przeciążanie operatora + tak, że jest on wrażliwy na wywoływanie w zaznaczonym lub niezaznaczonym kontekście


Tworzę strukturę numeryczną, więc przeciążam operatory arytmetyczne. Oto przykład do struktury, która reprezentuje 4-bitowego liczbę całkowitą bez znaku:

public struct UInt4 
{ 
    private readonly byte _value; 

    private const byte MinValue = 0; 
    private const byte MaxValue = 15; 

    public UInt4(int value) 
    { 
     if (value < MinValue || value > MaxValue) 
      throw new ArgumentOutOfRangeException("value"); 

     _value = (byte) value; 
    } 

    public static UInt4 operator +(UInt4 a, UInt4 b) 
    { 
     return new UInt4((a._value + b._value) & MaxValue); 
    } 
} 

przeciążone operator dodawania pozwala to kod:

var x = new UInt4(10); 
var y = new UInt4(11); 
var z = x + y; 

tu przepełnienia obliczeń, tak zmienna z ma wartość 5. Chciałbym również móc to zrobić:

var x = new UInt4(10); 
var y = new UInt4(11); 
var z = checked (x + y); 

Ta próbka powinna wywołać wyjątek OverflowException. Jak mogę to osiągnąć?

już ustalone, że sprawdzone kontekst nie obejmuje zwanych metod, tak, na przykład, nie rzucać, niezależnie od tego, czy to się nazywa w kratkę lub nierejestrowanego kontekstu:

public static UInt4 operator +(UInt4 a, UInt4 b) 
{ 
    int i = int.MaxValue; 

    //this should throw in a checked context, but when 
    //the operator is used in a checked context, this statement 
    //is nonetheless unchecked. 
    byte b = (byte)i; 

    return new UInt4((a._value + b._value) & MaxValue); 
} 

Is istnieje sposób zadeklarowania dwóch przeciążeń operatora dodawania, jeden sprawdzony, a drugi niezaznaczony? Ewentualnie, czy jest jakiś sposób, aby określić w czasie wykonywania kontekst wywołującego (co wydaje się mało prawdopodobne, ale pomyślałem, że mimo to zapytać), coś takiego:

public static UInt4 operator +(UInt4 a, UInt4 b) 
{ 
    byte result = (byte)(a._value + b._value); 

    if (result > MaxValue) 
     if (ContextIsChecked()) 
      throw new OverflowException(); 
     else 
      result &= MaxValue; 
    return new UInt4(result); 
} 

private static bool ContextIsChecked() 
{ 
    throw new NotImplementedException("Please help."); 
} 
+0

Oto odpowiedź http://stackoverflow.com/questions/2873765/how-to-find-out-the-current-overflow-checking-context, która mówi, że jest mniej lub bardziej niemożliwa ... Czekam, aby zobaczyć Twoje podejście ... –

+0

@AlexeiLevenkov odpowiedź, którą znalazłem również wskazuje, że jest to niemożliwe. Jednym z podejść, o którym pomyślałem, jest zdefiniowanie typów "UInt4Checked" i "UInt4Unchecked" z wyraźnymi konwersjami między nimi. – phoog

+0

Downvoter, proszę wyjaśnić. – phoog

Odpowiedz

2

According to MSDN, z checked i unchecked słów kluczowych dotyczy tylko modelu integral types. Dlatego nie można tworzyć własnych typów, które mogą wykorzystywać sprawdzone i niezaznaczone słowa kluczowe.

+1

Zamknij, więc +1, ale nie zamierzam zaakceptować tej odpowiedzi, ponieważ jest tak, ponieważ nie ma nic na pierwszej stronie, która określa "* wbudowane * typy integralne". Próbuję zdefiniować mój własny typ integralny, dlatego chcę, aby był on wrażliwy na kontekst zaznaczony/niezeznaczony. Innymi słowy, powinien istnieć wyraźny link na pierwszej stronie do dokumentacji wbudowanych typów integralnych, ale tak nie jest, więc uważam, że strona jest niejednoznaczna. Znalazłem jednoznaczne źródło i przyjmuję pierwszą odpowiedź, która ją przytacza. – phoog

+0

Myślę, że dostałem to. Dzieje się tak dlatego, że nie zastąpiłeś niejawnego operatora konwersji i nie możesz go przekonwertować na jeden z wbudowanych typów integralnych, takich jak [this SO thread] (http://stackoverflow.com/questions/7615113/define-custom-integer typu bazowego) sugeruje.Mimo że nie mogę znaleźć tego wyraźnie stwierdzonego nigdzie w MSDN, przypuszczam, że jest podobny do tego, jak działają instrukcje przełączania, jak wyjaśnia Eric Lippert na dole [tego wątku] (http://stackoverflow.com/questions/5154104/what-exact-are-integral-types). –

+0

O nie, to w ogóle nie jest. Prawidłowa odpowiedź brzmi "nie możesz tworzyć własnych typów ...". Rozważ: Jeśli utworzyłem niejawny operator konwersji na wbudowanym integralnym typie, uzyskałbym kontrolę nad przepełnieniem w stosunku do zakresu wbudowanego typu integralnego, a nie zakresu typu, który próbuję zdefiniować. Przykład w wątku SO, z którym łączysz, nie zostanie przeniesiony, gdy przepełni się w niezaznaczonym kontekście. – phoog