2013-04-02 11 views
7

W porządku, od jakiegoś czasu próbuję znaleźć jakiekolwiek informacje na ten temat. Zbudowałem małą klasę, aby zobaczyć, jak trudne są certyfikaty typu "hard-safe-enums" dla ciągów znaków, ponieważ chcę używać ich do nazw pól w bazie danych i takich. Nigdy nie podobało mi się, że wyliczenia mogą być używane tylko w liczbach całkowitych.
Mimo że zaimplementowałem w tej klasie implicit operator, za każdym razem, gdy spróbuję go użyć, otrzymuję wyjątek dotyczący nieprawidłowego rzutu. Brakuje mi tego, ponieważ w tym momencie nie widzę nic złego w moim kodzie.
Oto klasa:
C#: Niestandardowy niejawny operator rzutowania nie działa

/// <summary> 
/// SBool - type-safe-enum for boolean strings 
/// </summary> 
public sealed class SBool 
{ 

    private readonly String name; 
    private readonly int value; 

    // these guys were for conversions. They might work better in another case, 
    // but for this one, they weren't very helpful. 
    // ((I.e. they didn't work either.)) 
    //private static readonly Dictionary<SBool, String> stringsByBool = new Dictionary<SBool, String>(); 
    //private static readonly Dictionary<String, SBool> boolsByString = new Dictionary<String, SBool>(); 

    public static readonly SBool True = new SBool(1, "true"); 
    public static readonly SBool False = new SBool(0, "false"); 

    private SBool(int value, String name) 
    { 
     this.name = name; 
     this.value = value; 
     //stringsByBool[this] = name; 
     //boolsByString[name] = this; 
    } 

    private SBool(SBool sbool) 
    { 
     this.name = sbool.name; 
     this.value = sbool.value; 
     //stringsByBool[this] = name; 
     //boolsByString[name] = this; 
    } 

    public override String ToString() 
    { 
     return name; 
    } 

    /// <summary> 
    /// allows implicit casting of SBools to strings 
    /// </summary> 
    /// <param name="sbool">the SBool to cast into a string</param> 
    /// <returns>the string equivalent of the SBool (its value)</returns> 
    public static implicit operator String(SBool sbool) 
    { 
     if (sbool == SBool.True) 
      return SBool.True.name; 
     else 
      return SBool.False.name; 
    } 

    /// <summary> 
    /// implicitly cast a string into a SBool. 
    /// </summary> 
    /// <param name="str">the string to attempt to cast as a SBool</param> 
    /// <returns>the SBool equivalent of the string, 
    /// SBool.False if not either "true" or "false".</returns> 
    public static explicit operator SBool(String str) 
    { 
     if (!String.IsNullOrEmpty(str) && str.ToLower() == "true") 
      return SBool.True; 
     else 
      return SBool.False; 
    } 

    public static bool operator ==(SBool left, SBool right) 
    { 
     return left.value == right.value; 
    } 

    public static bool operator !=(SBool left, SBool right) 
    { 
     return left.value != right.value; 
    } 
} 


ta zawodzi na czeku zmiennej sesji:
if(((string)Session["variable"]) == SBool.False) z InvalidCastException,
a ja szczerze mówiąc nie mam pojęcia dlaczego.

Z góry dziękuję; pliki cookie dla każdego, kto może wyjaśnić, dlaczego to nie działa (pliki cookie nie są dostępne we wszystkich obszarach). Zamierzam naprawić inne rzeczy, ale daj mi znać, jeśli coś jest niejasne. Aby uzyskać więcej informacji na temat wyrażeń typu "Bezpieczny typ", oto one of the SO posts Oparłem tę klasę z.

[MetaEDIT] lekceważ to. Byłem strasznie, okropnie błędnie. [/ edit]

+1

Czy próbowałeś odlewania 'Session [„zmienna”]' na 'SBool' zamiast ciąg? Lub do 'string', a następnie' SBool'? –

+0

'sBool.False' jest wartością logiczną poprawną ...? jeśli sprawdzasz, czy jest równy, dlaczego nie rzucić tej wartości po prawej stronie '==' na 'if (((ciąg znaków) Session [" zmienna "]) == SBool.False.ToString()' ' Casting błąd jest poprawne btw' – MethodMan

+1

najprawdopodobniej wyjątkiem jest o tej obsadzie '(string) Session [„zmienna”]' – Lanorkin

Odpowiedz

5

Zdefiniowane przez użytkownika niejawne i jawne operatory są wyłącznie mechanizmem czasu kompilacji, a nie mechanizmem wykonawczym. Po skompilowaniu kodu środowisko wykonawcze nie ma pojęcia o żadnych zdefiniowanych przez użytkownika operatorach konwersji.

Kiedy kompilator robi, sprawdza typ i widzi, że Foo jest oczekiwany, ale rzeczywista wartość to Bar. Najpierw sprawdzi operatory konwersji niejawnej z wbudowanymi językami, aby zobaczyć, czy istnieje odpowiednia konwersja. Jeśli tak nie jest, sprawdza definicję zarówno dla niejawnych operatorów konwersji, jeśli znajdzie taki, który doda w wywołaniu odpowiedniej metody statycznej, aby wykonać konwersję. Po przejściu do środowiska wykonawczego zostaną zastosowane wbudowane niejawne operatory języka.

W tym przypadku nie są konwersji z SBool do string, jesteś konwersji z object do string (o ile dotyczy to kompilator) i nie ma operator konwersji do obsługi tego.

Najpierw należy rzucić wynik zmiennej Session na SBool (czyli taką, jaka jest naprawdę), a następnie do innego typu, aby móc wykorzystać operatorów konwersji zdefiniowanych przez użytkownika. A więc:

if(((SBool)Session["variable"]) == SBool.False) 

będzie działać dobrze.

+0

+1, jeśli zaimplementujesz niejawną konwersję z 'obiektu' na' SBool', czy umożliwi on niejawne rozpakowywanie? Prawdopodobnie nie ... byłoby drogie dla kompilatora, niepożądanych efektów ubocznych itp. – Jodrell

+0

@Jodrell To klasa, a nie struktura, więc nie ma tu boksowania. To powiedziawszy, nie ma powodu, aby nie można było dokonać konwersji między typem a obiektem. – Servy

+0

Jeśli tak, to dlaczego mój wyjątek powinien wyraźnie stwierdzać, że nieprawidłowa konwersja występuje pomiędzy 'SBool' i' System.String'? Gdyby pomyślał, że to "obiekt", czy nie powiedziałby tego zamiast "SBool" w komunikacie wyjątku? ((Przepraszamy, tekst wiadomości powinien być zawarty w oryginalnym wpisie.)) – FireSBurnsmuP

0

Wen podczas przesyłania Sesji [] na ciąg, dokonujesz wyraźnej konwersji. Nie masz zdefiniowanego operatora jawnego SBool-> String, tylko niejawny.

Musisz dodać jawną konwersję ciągów znaków SBool->.

+0

Nawet gdyby je dodał, to w ogóle by nie pomogło. – Servy

0

Jako że Servy wspomniał o tych typach obsady, zdarzają się one podczas kompilacji. Istnieje jednak sposób na wymuszenie tego sprawdzenia w środowisku wykonawczym za pomocą dynamicznego słowa kluczowego. Zamiast rzucać do obsady SBool do dynamicznej. Spowoduje to wykonanie rzutujących operatorów w czasie wykonywania.

Moim zdaniem odlewania do SBool jest czystsze i mniej podatne na błędy rozwiązanie.

Powiązane problemy