SORU
20 AĞUSTOS 2013, Salı


İnt kaldırdı/null dönüşüm ile ciddi hatalar, ondalık dönüştürme sağlar

Bu soru bana anlık şöhret burada Yığın Taşması üzerine getirecek bence.

Sanırım aşağıdaki türü vardır:

// represents a decimal number with at most two decimal places after the period
struct NumberFixedPoint2
{
    decimal number;

    // an integer has no fractional part; can convert to this type
    public static implicit operator NumberFixedPoint2(int integer)
    {
        return new NumberFixedPoint2 { number = integer };
    }

    // this type is a decimal number; can convert to System.Decimal
    public static implicit operator decimal(NumberFixedPoint2 nfp2)
    {
        return nfp2.number;
    }

    /* will add more nice members later */
}

Hassas kaybetme tek güvenli dönüşümleri izin olduğu gibi yazılmıştır. Bu kodu denediğimde ancak:

    static void Main()
    {
        decimal bad = 2.718281828m;
        NumberFixedPoint2 badNfp2 = (NumberFixedPoint2)bad;
        Console.WriteLine(badNfp2);
    }

Çalıştırıldığında bu derler şaşırdım ve,,yazar 2. int (değeri 2) NumberFixedPoint2 dönüştürme önemli. (System.Decimal alan WriteLine aşırı yüklenme kimseye harikalar ihtimaline karşı tercih edilir.)

Neden Yeryüzünde NumberFixedPoint2 12 *dönüştürme izin verilir? (Yukarıdaki kodu bu arada, eğer NumberFixedPoint2 bir sınıfa bir yapı değişirse, değişen bir şey yok.)

Biliyorsun eğer C# Dili özelliklerini yazan bir örtük dönüştürme int özel bir tür "ima" varlığı bir "doğrudan" açık dönüştürme decimal özel tip?

Çok daha kötü olur. Bu kod yerine deneyin:

    static void Main()
    {
        decimal? moreBad = 7.3890560989m;
        NumberFixedPoint2? moreBadNfp2 = (NumberFixedPoint2?)moreBad;
        Console.WriteLine(moreBadNfp2.Value);
    }

Gördüğünüz gibi, (kaldırdı) Nullable<> dönüşümler var. Ama evet, bu derleme yapıyor.

Derlenmiş zaman86"platform", bu kod öngörülemeyen sayısal bir değer yazar. Bir zaman zaman değişir. Bir keresinde bir örnek olarak aldım2289956. Şimdi, bu çok ciddi bir hata!

İçin derlenmiş64platform, yukarıdaki kodu mesaj ile System.InvalidProgramException ile uygulama çökerOrtak Dil çalışma Zamanı geçersiz bir program tespit edildi.InvalidProgramException sınıf: belgelere göre

Genellikle bu programı oluşturan derleyici bir hata olduğunu gösterir.

Herkes (Eric Lippert, veya C kaldırdı dönüşüm ile çalışmış biri gibi# derleyicisi) bu hataların neden biliyor musun? Gibi, ne bizim kod içine kaçmazlar bu yeterli bir koşul değil mi? Tipi nedeniyle NumberFixedPoint2 gerçek kod (diğer insanların para ve Malzeme Yönetimi) sahip olduğumuz bir şey aslında.

CEVAP
20 AĞUSTOS 2013, Salı


Sadece sorunun ilk bölümü ile başlamak yanıtlarken ediyorum. (İkinci bölümü ayrı bir soru olmalı öneririm; bir hata olması daha büyük bir ihtimal.)

Tek bir şey varaçık* *24, ama bu dönüşüm için decimal dönüştürme ediliyorörtülü olarakkodunuzda aradı. Dönüşüm bu IL olur:

IL_0010:  stloc.0
IL_0011:  ldloc.0
IL_0012:  call       int32 [mscorlib]System.Decimal::op_Explicit(valuetype [mscorlib]System.Decimal)
IL_0017:  call       valuetype NumberFixedPoint2 NumberFixedPoint2::op_Implicit(int32)

Bu olduğuna inanıyorumdoğruşaşırtıcı olsa da spec göre bir davranış1. Hadi işe C bölüm 6.4.5 yolumuzu# 4 spec (Kullanıcı Tanımlı bir Açık Dönüşüm). Sadece ilgili sonuçları bizim durumumuzda ne sıkıcı olurdu gibi tüm metni kopyalamak için gidiyor değilim. Aynı şekilde iyi kod yazı tipi ile burada işe yaramıyor gibi alt simgeler,:) kullanacağım

  • Türleri S0 T0 belirler: S0 decimal T0 NumberFixedPoint2.
  • Hangi kullanılan tanımlı dönüştürme operatörleri olarak kabul edilecektir türlerinin, D bul: { decimal, NumberFixedPoint2 }
  • -Kullanıcı tanımlı ve kaldırdı uygulanabilir dönüşüm operatörlerin kümesi, Ubul. decimalkapsardecimal 37 *standart örtülü bir dönüşüm var çünkü int (bölüm 6.4.3). Açık dönüştürme operatörüU, ve gerçekten U tek üyesi
  • En özel kaynak türü, Sx, Uoperatör bul
    • Operatör ilk kurşunun dışarı yani S (decimal) dönüştürmek değildir
    • Operatör ikinci mermi dışarı yani S (decimal kapsar int, tersi değil) kapsayan bir tür dönüştürmek değildir
    • O sadece "en çok türü kapsayan" - evet, sadece bir tür var, yani sorun yok: 48* *int. hakkında görüşmeler üçüncü kurşun, yaprakları
  • En belirli bir hedef türü, Tx, Uoperatör bul
    • Operatör Tx NumberFixedPoint2 doğru NumberFixedPoint2 oturumlar.
  • Bulmak en özel dönüştürme operatörü:
    • U en özel operatör gerçekten Tx Sx çok dönüştürmek sağlayan tam bir operatör içerir
  • Son olarak, dönüşüm uygulayın:
    • S Sx Sx 60 *standart açık bir dönüştürme işlemi.(decimal int.)
    • En belirli kullanıcı tanımlı dönüştürme operatörü çağrılan (operatör)
    • Üçüncü kurşun dönüşüm için gerek yok yani T Tx

Kalın çizgi standart açık bir dönüşüm gerçekten uygun olduğunu teyit eden, farklı bir türünden sadece açık bir dönüşüm aslında belirtildiğinde bit.


1Peki bu şaşırtıcı, en azından buldum. Bunu daha önce gördüğümü farkında değilim.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • olinerd

    olinerd

    23 AĞUSTOS 2007
  • Peter Sharp

    Peter Sharp

    11 ŞUBAT 2013
  • Phandroid

    Phandroid

    26 Ocak 2009