C # veya .NET'te gördüğünüz en garip köşe durumu nedir? [kapalı]


322

Birkaç köşe vakası ve zeka oyunları topluyorum ve her zaman daha fazlasını duymak istiyorum. Sayfa sadece gerçekten C # dil bitleri ve bobs kapsar, ama aynı zamanda temel .NET şeyler de ilginç buluyorum. Örneğin, sayfada olmayan ama inanılmaz bulduğum bir tanesi:

string x = new string(new char[0]);
string y = new string(new char[0]);
Console.WriteLine(object.ReferenceEquals(x, y));

Yanlış yazdırmak için beklenir - sonuçta, "yeni" (bir başvuru türü ile) her zaman yeni bir nesne oluşturur, değil mi? Hem C # hem de CLI için teknik özellikler olması gerektiğini belirtir. Bu durumda değil. True yazdırır ve test ettiğim çerçevenin her sürümü üzerinde yapmıştır. (Mono'da denemedim, kuşkusuz ...)

Açık olmak gerekirse, bu sadece aradığım şeylere bir örnektir - özellikle bu tuhaflığın tartışmasını / açıklamasını aramıyordum. (Normal dize stajyeni ile aynı değildir; özellikle, dize stajyerliği normalde bir kurucu çağrıldığında gerçekleşmez.) Gerçekten benzer garip davranışlar istiyordum.

Dışarıda gizlenen başka taşlar var mı?


64
Mono 2.0 rc üzerinde test edilmiştir; True döndürür
Marc Gravell

10
Her iki dizeleri string.Empty olma sonunda ve çerçeve buna yalnızca bir referans tutar görünür
Adrian Zanescu

34
Bu bir hafıza koruma şeyidir. Statik yöntem dizesi için MSDN belgelerine bakın. CLR, bir dize havuzunu korur. Bu yüzden aynı içeriğe sahip dizeler aynı belleğe, yani nesneye referanslar olarak görünür.
John Leidegren

12
@John: Dize stajlaması yalnızca değişmez değerler için otomatik olarak gerçekleşir . Burada durum böyle değil. @DanielSwe: Dizeleri değişmez kılmak için stajyerlik gerekmez . Mümkün olması, değişmezliğin güzel bir sonucudur, ancak normal stajyerlik burada gerçekleşmez.
Jon Skeet

3
Bu davranışa neden olan uygulama ayrıntıları burada açıklanmıştır: blog.liranchen.com/2010/08/brain-teasing-with-strings.html
Liran

Yanıtlar:


394

Sanırım bunu daha önce gösterdim, ama buradaki eğlenceyi seviyorum - bu takip etmek için bazı hata ayıklama aldı! (orijinal kod açıkça daha karmaşık ve ince idi ...)

    static void Foo<T>() where T : new()
    {
        T t = new T();
        Console.WriteLine(t.ToString()); // works fine
        Console.WriteLine(t.GetHashCode()); // works fine
        Console.WriteLine(t.Equals(t)); // works fine

        // so it looks like an object and smells like an object...

        // but this throws a NullReferenceException...
        Console.WriteLine(t.GetType());
    }

Peki T ...

Cevap: Herhangi biri Nullable<T>- gibi int?. Olamayan GetType () dışında tüm yöntemler geçersiz kılınır; böylece object.GetType () ... öğesini çağırmak için nesneye (ve dolayısıyla null değerine) dönüştürülür (kutulu); null ;-p


Güncelleme: arsa kalınlaşıyor ... Ayende Rahien blogunda da benzer bir zorluk yaşadı , ancak where T : class, new():

private static void Main() {
    CanThisHappen<MyFunnyType>();
}

public static void CanThisHappen<T>() where T : class, new() {
    var instance = new T(); // new() on a ref-type; should be non-null, then
    Debug.Assert(instance != null, "How did we break the CLR?");
}

Ama yenilebilir! Uzaklaştırma gibi şeyler tarafından kullanılan aynı dolaylı kullanımı; uyarı - aşağıdaki saf kötülüktür :

class MyFunnyProxyAttribute : ProxyAttribute {
    public override MarshalByRefObject CreateInstance(Type serverType) {
        return null;
    }
}
[MyFunnyProxy]
class MyFunnyType : ContextBoundObject { }

Bu durumda, new()çağrı MyFunnyProxyAttributedönen proxy'ye ( ) yönlendirilir null. Şimdi git ve gözlerini yıka!


9
Nullable <T> .GetType () neden tanımlanamıyor? Sonuç tür olmamalı mı (Nullable <T>)?
Drew Noakes

69
Drew: Sorun GetType () sanal değildir, bu yüzden geçersiz kılınmaz - bu, değerin yöntem çağrısı için kutulu olduğu anlamına gelir. Kutu null referans olur, dolayısıyla NRE olur.
Jon Skeet

10
@Çizdi; buna ek olarak, Nullable <T> için özel boks kuralları vardır, bu da boş bir Nullable <T> kutusunun null'a boş olduğu anlamına gelir, boş bir Nullable <T> içeren bir kutu değil (boş bir Nullable <T >)
Marc Gravell

29
Çok çok havalı. Soğuk bir şekilde. ;-)
Konrad Rudolph

6
Oluşturucu-kısıtlama, 10.1.5 C # 3.0 dil spesifikasyonunda
Marc Gravell

216

Bankacılar Yuvarlama.

Bu bir derleyici hatası veya arızası değil, kesinlikle garip bir köşe durumu ...

Net Framework, Banker's Rounding olarak bilinen bir şema veya yuvarlama kullanır.

Bankacılar Yuvarlama'da 0.5 sayılar en yakın çift sayıya yuvarlanır,

Math.Round(-0.5) == 0
Math.Round(0.5) == 0
Math.Round(1.5) == 2
Math.Round(2.5) == 2
etc...

Bu, daha iyi bilinen Round-Half-Up yuvarlamaya dayalı finansal hesaplamalarda bazı beklenmedik hatalara yol açabilir.

Bu, Visual Basic için de geçerlidir.


22
Bana da garip geldi. En azından büyük bir sayı listesi yuvarlayana ve toplamlarını hesaplayana kadar. Daha sonra, basitçe yuvarlarsanız, yuvarlanmamış sayıların toplamından potansiyel olarak büyük bir farkla sonuçlanacağınızı anlıyorsunuz. Finansal hesaplamalar yapıyorsanız çok kötü!
Tsvetomir Tsonev

255
İnsanların bilmemesi durumunda şunları yapabilirsiniz: Math.Round (x, MidpointRounding.AwayFromZero); Yuvarlama şemasını değiştirmek için.
ICR

26
Dokümanlardan: Bu yöntemin davranışı IEEE Standard 754, bölüm 4'ü izler. Bu tür yuvarlamaya bazen en yakın yuvarlama veya bankacının yuvarlanması denir. Bir orta nokta değerinin sürekli olarak tek bir yönde yuvarlanmasından kaynaklanan yuvarlama hatalarını en aza indirir.
ICR

8
Merak ediyorum, bu yüzden int(fVal + 0.5)yerleşik yuvarlama işlevine sahip dillerde bile çok sık görüyorum .
Ben Blank

32
İronik bir şekilde, bir keresinde bir bankada çalıştım ve diğer programcılar bu konuda yuvarlanmaya başladılar, yuvarlamanın çerçeve içinde kırıldığını düşünüyorlar
dan

176

Bu işlev olarak adlandırılırsa Rec(0)(hata ayıklayıcı altında değil) ne yapacak ?

static void Rec(int i)
{
    Console.WriteLine(i);
    if (i < int.MaxValue)
    {
        Rec(i + 1);
    }
}

Cevap:

  • 32 bit JIT üzerinde bir StackOverflowException ile sonuçlanmalıdır
  • 64 bit JIT'de tüm sayıları int'e yazdırmalıdır.

Bunun nedeni , 64 bit JIT derleyicisinin kuyruk çağrısı optimizasyonunu uygularken 32 bit JIT'in uygulamadığıdır.

Ne yazık ki bunu doğrulamak için elimde 64-bit bir makinem yok, ancak yöntem kuyruk çağrısı optimizasyonu için tüm koşulları karşılıyor. Eğer birisi varsa, bunun doğru olup olmadığını görmek isterim.


10
Sürüm modunda derlenmesi gerekir, ancak kesinlikle x64 =) üzerinde çalışır
Neil Williams

3
mevcut tüm JIT'ler TCO'yu Yayınlama modunda yapacaklarından VS 2010 çıktığında yanıtınızı güncellemeye değer olabilir
ShuggyCoUk

3
Sadece 32 bit WinXP'de VS2010 Beta 1'de denedim. Yine de bir StackOverflowException alın.
squillman

130
StackOverflowException için +1
calvinlough

7
O ++tamamen beni orada attı. Eğer arayamaz Rec(i + 1)normal bir insan gibi?
yapılandırıcı

111

Bunu Ata!


Bu, partilere sormayı sevdiğim bir şeydir (muhtemelen bu yüzden artık davet edilmiyorum):

Aşağıdaki kod parçasını derleyebilir misiniz?

    public void Foo()
    {
        this = new Teaser();
    }

Kolay bir hile olabilir:

string cheat = @"
    public void Foo()
    {
        this = new Teaser();
    }
";

Ancak asıl çözüm şudur:

public struct Teaser
{
    public void Foo()
    {
        this = new Teaser();
    }
}

Dolayısıyla, değer türlerinin (yapıların) thisdeğişkenlerini yeniden atayabileceği biraz bilinir .


3
C ++ sınıfları da bunu yapabilir ... Ben son zamanlarda biraz keşfettiğim gibi, sadece bir optimizasyon için kullanmaya çalıştığınız için
bağırmak

1
Aslında yerinde yeni kullanıyordum. Sadece tüm alanları güncellemek için etkili bir yol istedim :)
mpen

70
Bu da bir hile: //this = new Teaser();:-)
AndrewJacksonZA 18:06

17
:-) Üretim kodumdaki bu hileleri, bu yeniden atama iğrençliğinden daha çok tercih ederim ...
Ömer Mor

2
CLR'den C # ile: Bunu yapmasının nedeni, başka bir kurucudaki bir yapının parametresiz yapıcısını çağırabilmenizdir. Bir yapının yalnızca bir değerini başlatmak ve diğer değerlerin sıfır / boş (varsayılan) olmasını istiyorsanız, yazabilirsiniz public Foo(int bar){this = new Foo(); specialVar = bar;}. Bu etkili değildir ve gerçekten haklı değildir ( specialVariki kez atanır), sadece FYI. (Bu kitapta verilen sebep, neden sadece yapmamamız gerektiğini bilmiyorum public Foo(int bar) : this())
kizzx2

100

Birkaç yıl önce, sadakat programı üzerinde çalışırken, müşterilere verilen puan miktarı ile ilgili bir sorun yaşadık. Sorun döküm / çift int için dönüştürme ile ilgili.

Aşağıdaki kodda:

double d = 13.6;

int i1 = Convert.ToInt32(d);
int i2 = (int)d;

i1 == i2 mi?

Görünen o ki i1! = İ2. Convert ve cast operatörünün farklı yuvarlama politikaları nedeniyle gerçek değerler şunlardır:

i1 == 14
i2 == 13

Math.Ceiling () veya Math.Floor () (veya MidpointRounding ile Math.Rounding'i gereksinimlerimizi karşılayan) aramak her zaman daha iyidir.

int i1 = Convert.ToInt32( Math.Ceiling(d) );
int i2 = (int) Math.Ceiling(d);

44
Bir tamsayıya dökmek yuvarlanmaz, sadece keser (etkili bir şekilde her zaman aşağı yuvarlanır). Yani bu tam mantıklı.
Max Schmeling

57
@ Max: evet, ama neden dönüşüyor?
Stefan Steinegger

18
@Stefan Steinegger Yaptığı tek şey, ilk etapta bunun için bir sebep olmazdı, değil mi? Ayrıca sınıf adının Dönüştürme Değil Dönüştür olduğunu unutmayın.
bug-a-lot

3
VB'de: CInt () turları. Fix () kesiliyor. Beni bir kez yaktılar ( blog.wassupy.com/2006/01/i-can-believe-it-not-truncating.html )
Michael Haren

74

Bir enum işlevi aşırı yükü olsa bile 0'ı bir tamsayı yapmalıydı.

0 # enum eşlemek için C # çekirdek takım mantığını biliyordum, ama yine de olması gerektiği gibi dik değil. Npgsql'den bir örnek .

Test örneği:

namespace Craft
{
    enum Symbol { Alpha = 1, Beta = 2, Gamma = 3, Delta = 4 };


   class Mate
    {
        static void Main(string[] args)
        {

            JustTest(Symbol.Alpha); // enum
            JustTest(0); // why enum
            JustTest((int)0); // why still enum

            int i = 0;

            JustTest(Convert.ToInt32(0)); // have to use Convert.ToInt32 to convince the compiler to make the call site use the object version

            JustTest(i); // it's ok from down here and below
            JustTest(1);
            JustTest("string");
            JustTest(Guid.NewGuid());
            JustTest(new DataTable());

            Console.ReadLine();
        }

        static void JustTest(Symbol a)
        {
            Console.WriteLine("Enum");
        }

        static void JustTest(object o)
        {
            Console.WriteLine("Object");
        }
    }
}

18
Vay canına, bu benim için yeni bir tane. Ayrıca ConverTo.ToIn32 () nasıl çalıştığını, ancak (int) 0'a yayın yapmanın ne kadar garip olduğunu. Ve başka herhangi bir sayı> 0 çalışır. ("Çalışır" ile cisim aşırı yüklenmesini kastediyorum.)
Lucas

Bu davranış etrafında iyi uygulamaları uygulamak için bir kod çözümleme kuralı vardır: msdn.microsoft.com/en-us/library/ms182149%28VS.80%29.aspx Bu bağlantı aynı zamanda 0 eşlemenin nasıl çalıştığının güzel bir açıklamasını içerir .
Chris Clark

1
@Chris Clark: Enum Symbol'e None = 0 koymaya çalıştım. hala derleyici 0 ve hatta (int) 0 için enum seçiyor
Michael Buen

2
IMO none, herhangi bir numaraya dönüştürülebilen ve her zaman int yapan ve örtük olarak bir numaralamaya dönüştürülemeyen bir anahtar kelime eklemeliydi .
CodesInChaos

5
ConverTo.ToIn32 () işlevi, sonuçların derleme sabiti olmadığı için çalışır. Ve sadece 0 derleme sabiti bir enuma dönüştürülebilir. .Net'in önceki sürümlerinde, yalnızca değişmez değerler bile 0numaralandırılabilir olmalıdır. Eric Lippert'in
CodesInChaos

67

Bu şimdiye kadar gördüğüm en alışılmadık biri (elbette buradakiler dışında!):

public class Turtle<T> where T : Turtle<T>
{
}

Bunu beyan etmenizi sağlar, ancak gerçek bir kullanımı yoktur, çünkü her zaman merkezde doldurduğunuz sınıfı başka bir Kaplumbağa ile sarmanızı isteyecektir.

[şaka] Sanırım bütün kaplumbağalar aşağı ... [/ şaka]


34
Yine de örnekler oluşturabilirsiniz:class RealTurtle : Turtle<RealTurtle> { } RealTurtle t = new RealTurtle();
Marc Gravell

24
Aslında. Bu Java'nın büyük etki yaratmak için kullandığı modeldir. Protokol Tamponlarında da kullanıyorum.
Jon Skeet

6
RCIX, oh evet öyle.
Joshua

8
Bu modeli süslü jenerik eşyalarda oldukça fazla kullandım. Doğru yazılmış bir klon gibi şeylere izin verir veya kendi örneklerini oluşturur.
Lucero

20
Bu 'merakla yinelenen şablon kalıbı' en.wikipedia.org/wiki/Curiously_recurring_template_pattern
porges

65

İşte son zamanlarda öğrendiğim biri ...

interface IFoo
{
   string Message {get;}
}
...
IFoo obj = new IFoo("abc");
Console.WriteLine(obj.Message);

Yukarıdaki ilk bakışta deli görünüyor, ama aslında yasal bir anahtar bölümünü özledik rağmen (gerçekten, yer.Hiçbir ama değil "denilen bir sınıf eklemek gibi bir şey hacky IFoo" ya da "bir ekleme usingnoktasına takma IFooa at sınıf").

Neden olduğunu anlayabiliyor musun, o zaman: Kim bir arayüz başlatamayacağınızı söylüyor?


1
"Kullanarak takma" için 1 - Yaptığın bilmezdim o !
David

COM Interop :-) için derleyiciyi
hackleyin

Seni p * ç! En azından "belirli koşullar altında" diyebilirdin ... Derleyicim çürütür!
MA Hanin

56

Ne zaman Boole ne Doğru ne de Yanlıştır?

Bill, bir Boole'yi hackleyebileceğinizi keşfetti, böylece A True ve B True ise (A ve B) False olur.

Saldırıya uğramış Booleans


134
Tabii ki FILE_NOT_FOUND olduğunda!
Greg

12
Bu ilginçtir, çünkü matematiksel olarak, C # 'da hiçbir ifadenin kanıtlanamayacağı anlamına gelir. Hata.
Simon Johnson

20
Bir gün bu davranışa bağlı bir program yazacağım ve en karanlık cehennem şeytanları benim için bir karşılama hazırlayacak. Bwahahahahaha!
Jeffrey L Whitledge

18
Bu örnek mantıksal işleçleri değil bitsel kullanır. Bu nasıl şaşırtıcı?
Josh Lee

6
Yapının düzenini hackliyor, elbette garip sonuçlar alacaksınız, bu şaşırtıcı veya beklenmedik değil!
Ion Todirel

47

Partiye biraz geç geliyorum, ama üç dört beş var:

  1. InvokeRequired uygulamasını yüklenmemiş / gösterilmemiş bir denetimde yoklarsanız, yanlış - ve başka bir iş parçacığından değiştirmeye çalışırsanız yüzünüzde havaya uçar ( çözüm buna başvurmaktır. kontrol).

  2. Beni harekete geçiren bir diğeri ise aşağıdakilerle bir montaj verildi:

    enum MyEnum
    {
        Red,
        Blue,
    }

    başka bir derlemede MyEnum.Red.ToString () yöntemini hesaplarsanız ve zaman zaman birisi numaralandırmanızı yeniden derlediğinde:

    enum MyEnum
    {
        Black,
        Red,
        Blue,
    }

    çalışma zamanında, "Siyah" alacaksınız.

  3. Bazı kullanışlı sabitleri ile paylaşılan bir montaj vardı. Selefim çirkin görünümlü sadece özelliklerin bir yük bırakmıştı, ben dağınıklığı kurtulmak ve sadece kamu const kullanmak düşündüm. VS onları referanslara değil, değerlerine derlediğinde biraz şaşırdım.

  4. Eğer montaj başka bir arayüzün yeni bir yöntem uygulamak, ancak montaj o eski sürümünü başvuran yeniden, size rağmen durumuna bir özel ( 'NewMethod' hiçbir uygulanmasını) almak var (bkz onu hayata buraya ).

  5. Sözlük <,>: "Öğelerin döndürülme sırası tanımsız". Bu korkunç , çünkü bazen ısırıyor olabilir, ama başkalarını çalıştırabilir ve eğer Sözlük'ün güzel oynayacağını körü körüne varsaydıysanız ("neden olmasın? Düşündüm, Liste yapar"), gerçekten nihayet varsayımınızı sorgulamaya başlamadan önce burnunuzu içine alın.


6
# 2 ilginç bir örnektir. Numaralandırmalar, integral değerlerle derleyici eşlemeleridir. Açıkça değerleri atamasanız bile, derleyici MyEnum.Red = 0 ve MyEnum.Blue = 1 ile sonuçlanır. Siyah eklediğinizde, 0 değerini Kırmızı ile Siyah arasında eşleştirmek için 0 değerini yeniden tanımladınız. Sorunun, Serileştirme gibi diğer kullanımlarda da ortaya çıkacağından şüpheleniyorum.
LBushkin

3
Çağırma için +1 gerekir. Bizimkilerinizde, Red = 1, Blue = 2 gibi numaralara açık bir şekilde değerler atamayı tercih ediyoruz, böylece yeni bir değer her zaman aynı değerle sonuçlanmadan önce veya sonra eklenebilir. Veritabanlarına değerler kaydediyorsanız özellikle gereklidir.
TheVillageIdiot

53
# 5'in bir "uç dava" olduğuna katılmıyorum. Değer eklediğinizde, sözlüğün tanımlı bir sırası olmamalıdır. Tanımlanmış bir sipariş istiyorsanız, bir Liste kullanın veya sizin için yararlı bir şekilde sıralanabilecek bir anahtar kullanın veya tamamen farklı bir veri yapısı kullanın.
Kama

21
@Wedge, belki SortedDictionary gibi?
Allon Guralnek

4
# 3 sabitler kullanıldıkları her yere sabit bilgi olarak eklendiğinden (en azından C # olarak) gerçekleşir. Selefiniz zaten fark etmiş olabilir, bu yüzden sadece get özelliğini kullandılar. Bununla birlikte, salt okunur bir değişken (bir sabitin aksine) de işe yarayacaktır.
Remoun

33

VB.NET, nullables ve üçlü operatör:

Dim i As Integer? = If(True, Nothing, 5)

Beklediğim beri bu hata ayıklamak için bana biraz zaman aldı iiçermesi Nothing.

Gerçekten ne içeriyorum? 0.

Bu şaşırtıcı ama aslında "doğru" davranış: NothingVB.NET nullCLR ile tam olarak aynı değildir : bağlama bağlı olarak, Nothingya ortalama nullya da default(T)bir değer türü Tiçin olabilir. Yukarıdaki durumda, Ifçıkarır Integerortak türü olarak Nothingve 5, bu yüzden, bu durumda, Nothingaracı 0.


İlginç olan bu cevabı bulamadım, bu yüzden bir soru oluşturmak zorunda kaldım . Peki, cevabın bu konuda olduğunu kim bilebilirdi?
GSerg

28

İlkini uzun bir vuruşla yenen gerçekten garip bir köşe davası buldum.

String.Equals Yöntemi (String, String, StringComparison) aslında yan etkisi ücretsiz değildir.

Bazı işlev üstündeki bir satırda bu vardı kod bloğu üzerinde çalışıyordu:

stringvariable1.Equals(stringvariable2, StringComparison.InvariantCultureIgnoreCase);

Bu satırı kaldırmak, programda başka bir yerde yığın taşmasına neden olur.

Kod, aslında bir BeforeAssemblyLoad olayı için bir işleyici yüklediği ve yapmaya çalıştığı ortaya çıktı

if (assemblyfilename.EndsWith("someparticular.dll", StringComparison.InvariantCultureIgnoreCase))
{
    assemblyfilename = "someparticular_modified.dll";
}

Şimdiye kadar sana söylemem gerekmemeliydi. Daha önce bir dize karşılaştırmasında kullanılmayan bir kültürün kullanılması bir montaj yüküne neden olur. InvariantCulture bunun bir istisnası değildir.


Sanırım BeforeAssemblyLoad ile gözlemleyebildiğiniz için "montajın yüklenmesi" bir yan etkidir!
Jacob Krall

2
Vay. Bu, koruyucunun bacağına mükemmel bir atış. Bir BeforeAssemblyLoad işleyicisi yazmak, bu tür sürprizlere yol açabilir.
wigy

20

Aşağıda "Korumalı belleği okuma veya yazma denemesi. Bu genellikle diğer belleğin bozuk olduğunu gösteren" hata iletisine neden olan bir yapı oluşturabileceğinize bir örnektir. Başarı ve başarısızlık arasındaki fark çok incedir.

Aşağıdaki birim testi sorunu gösterir.

Neyin yanlış gittiğini çözüp çözemeyeceğinize bakın.

    [Test]
    public void Test()
    {
        var bar = new MyClass
        {
            Foo = 500
        };
        bar.Foo += 500;

        Assert.That(bar.Foo.Value.Amount, Is.EqualTo(1000));
    }

    private class MyClass
    {
        public MyStruct? Foo { get; set; }
    }

    private struct MyStruct
    {
        public decimal Amount { get; private set; }

        public MyStruct(decimal amount) : this()
        {
            Amount = amount;
        }

        public static MyStruct operator +(MyStruct x, MyStruct y)
        {
            return new MyStruct(x.Amount + y.Amount);
        }

        public static MyStruct operator +(MyStruct x, decimal y)
        {
            return new MyStruct(x.Amount + y);
        }

        public static implicit operator MyStruct(int value)
        {
            return new MyStruct(value);
        }

        public static implicit operator MyStruct(decimal value)
        {
            return new MyStruct(value);
        }
    }

Kafam acıyor ... Bu neden çalışmıyor?
jasonh

2
Hm bunu birkaç ay önce yazdım, ama tam olarak neden olduğunu hatırlayamıyorum.
cbp

10
Derleyici bir hata gibi görünüyor; += 500aramaları: ldc.i4 500(bir ınt32 olarak 500 iter), daha sonra call valuetype Program/MyStruct Program/MyStruct::op_Addition(valuetype Program/MyStruct, valuetype [mscorlib]System.Decimal)- bir şekilde daha sonra muamele o kadar decimalherhangi bir dönüştürme olmadan (96 bit). Eğer kullanırsanız += 500Mdoğru olur. Derleyici bunu bir şekilde yapabileceğini düşünüyor gibi görünüyor (muhtemelen dolaylı int operatörü nedeniyle) ve sonra başka bir şekilde yapmaya karar veriyor.
Marc Gravell

1
Çifte gönderi için üzgünüm, işte daha nitelikli bir açıklama. Bunu ekleyeceğim, bunun biraz bitmiş ve neden olduğunu anlasam bile bu berbat. Bana göre bu, yapı / değer türünün talihsiz bir sınırlamasıdır. bytes.com/topic/net/answers/…
Bennett Dill

2
@ Derleyici hataları alıyorsanız veya orijinal yapıyı etkilemeyen değişiklikler iyidir. Erişim ihlali oldukça farklı bir yaratıktır. Sadece güvenli saf yönetilen kod yazıyorsanız, çalışma zamanı asla atmamalıdır.
CodesInChaos

18

C #, diziler çok boyutlu olmadığı ve türler ile türler arasında bir miras ilişkisi olduğu sürece diziler ve listeler arasındaki dönüşümleri destekler

object[] oArray = new string[] { "one", "two", "three" };
string[] sArray = (string[])oArray;

// Also works for IList (and IEnumerable, ICollection)
IList<string> sList = (IList<string>)oArray;
IList<object> oList = new string[] { "one", "two", "three" };

Bunun çalışmadığını unutmayın:

object[] oArray2 = new int[] { 1, 2, 3 }; // Error: Cannot implicitly convert type 'int[]' to 'object[]'
int[] iArray = (int[])oArray2;            // Error: Cannot convert type 'object[]' to 'int[]'

11
IList <T> örneği sadece bir dökümdür, çünkü string [] zaten ICloneable, IList, ICollection, IEnumerable, IList <string>, ICollection <string> ve IEnumerable <string> 'i uygular.
Lucas

15

Bu kazayla karşılaştığım en garip şey:

public class DummyObject
{
    public override string ToString()
    {
        return null;
    }
}

Aşağıdaki gibi kullanılır:

DummyObject obj = new DummyObject();
Console.WriteLine("The text: " + obj.GetType() + " is " + obj);

A atar NullReferenceException. Birden çok eklemenin C # derleyicisi tarafından çağrılması için derlendiği ortaya çıktı String.Concat(object[]). .NET 4'ten önce, yalnızca Concat'ın aşırı yüklenmesinde, nesnenin boş olup olmadığı denetlenir, ancak ToString () sonucu değil, bir hata vardır:

object obj2 = args[i];
string text = (obj2 != null) ? obj2.ToString() : string.Empty;
// if obj2 is non-null, but obj2.ToString() returns null, then text==null
int length = text.Length;

Bu ECMA-334 §14.7.4'ün bir hatasıdır:

İkili + işleci, işlenenlerden biri veya her ikisi de tür olduğunda dize birleştirme işlemini gerçekleştirir string. Dize birleştirme işleneni nullboş bir dize ile değiştirilir. Aksi takdirde, dize olmayan herhangi bir işlenen, ToStringtürden devralınan sanal yöntem çağrılarak dize temsiline dönüştürülür object. Eğer ToStringdönüşleri null, boş bir dize ikame edilir.


3
Hmm, ama bu hatayı .ToStringgerçekten asla null, ancak string.Empty dönmesi gerektiği gibi hayal edebiliyorum . Yine de çerçeve içinde hata.
Dykam

12

İlginç - ilk baktığımda C # derleyicisinin kontrol ettiği bir şey olduğunu düşündüğümde, ancak doğrudan herhangi bir parazit olasılığını kaldırmak için IL'yi yayarsanız bile, hala gerçekleşen newobjop-kodu olduğu anlamına gelir . kontrol etme.

var method = new DynamicMethod("Test", null, null);
var il = method.GetILGenerator();

il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Newarr, typeof(char));
il.Emit(OpCodes.Newobj, typeof(string).GetConstructor(new[] { typeof(char[]) }));

il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Newarr, typeof(char));
il.Emit(OpCodes.Newobj, typeof(string).GetConstructor(new[] { typeof(char[]) }));

il.Emit(OpCodes.Call, typeof(object).GetMethod("ReferenceEquals"));
il.Emit(OpCodes.Box, typeof(bool));
il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new[] { typeof(object) }));

il.Emit(OpCodes.Ret);

method.Invoke(null, null);

Ayrıca eşittir truekarşı eğer kontrol string.Emptybu op-kod stajyer boş olarak özel bir davranış olması gerekir hangi araçlar.


akıllı bir aleck ya da başka bir şey olmamak ama reflektörü duydunuz mu? bu tür durumlarda oldukça kullanışlıdır;
RCIX

3
Akıllı değilsin; noktayı kaçırıyorsunuz - bu vaka için belirli bir IL oluşturmak istedim. Her neyse, Reflection.Emit'in bu tür bir senaryo için önemsiz olduğu göz önüne alındığında, muhtemelen C #'da bir program yazmak, sonra reflektörü açmak, ikiliyi bulmak, yöntemi bulmak, vb ... kadar hızlıdır ... yapmak için IDE bırakın.
Greg Beech

10
Public Class Item
   Public ID As Guid
   Public Text As String

   Public Sub New(ByVal id As Guid, ByVal name As String)
      Me.ID = id
      Me.Text = name
   End Sub
End Class

Public Sub Load(sender As Object, e As EventArgs) Handles Me.Load
   Dim box As New ComboBox
   Me.Controls.Add(box)          'Sorry I forgot this line the first time.'
   Dim h As IntPtr = box.Handle  'Im not sure you need this but you might.'
   Try
      box.Items.Add(New Item(Guid.Empty, Nothing))
   Catch ex As Exception
      MsgBox(ex.ToString())
   End Try
End Sub

Çıktı "Korumalı belleği okumaya çalışıldı. Bu, diğer belleğin bozuk olduğunu gösterir."


1
İlginç! Derleyici bir hata gibi görünüyor; C # için taşıdım ve iyi çalışıyor. Bununla birlikte, Yük'te atılan istisnalar ile ilgili birçok sorun vardır ve hata ayıklayıcı ile / hata ayıklayıcı olmadan farklı davranır - bir hata ayıklayıcı ile yakalayabilirsiniz, ancak olmadan (bazı durumlarda) değil.
Marc Gravell

Üzgünüm, unuttum, açılan kutudan önce forma eklemeniz gerekiyor.
Joshua

Bu, bir tür korkunç iç iletişim mekanizması olarak bir SEH kullanarak diyalog başlatma ile mi ilgili? Win32'de böyle bir şeyi hatırlıyorum.
Daniel Earwicker

1
Bu aynı sorun cbp yukarıdaki. Döndürülen değer türü bir kopyadır, bu nedenle adı geçen kopyadan kaynaklanan herhangi bir özelliğe yapılan atıflar bit kova alanına yönlendirilir ... bytes.com/topic/net/answers/…
Bennett Dill

1
Hayır! Burada yapı yok. Aslında hata ayıkladım. Gecikmeli kilitlenmeye neden olan yerel birleşik giriş kutusunun liste öğesi koleksiyonuna bir NULL ekler.
Joshua

10

PropertyInfo.SetValue (), numaralandırmalara ints, null olabilen ints'a ints, nullable inumlara enums atayabilir, ancak nullable inumlara ints atayamaz.

enumProperty.SetValue(obj, 1, null); //works
nullableIntProperty.SetValue(obj, 1, null); //works
nullableEnumProperty.SetValue(obj, MyEnum.Foo, null); //works
nullableEnumProperty.SetValue(obj, 1, null); // throws an exception !!!

Tam açıklama burada


10

Tür argümanlarına bağlı olarak belirsiz hale getirilebilecek yöntemlere sahip genel bir sınıfınız varsa ne olur? Son zamanlarda iki yönlü bir sözlük yazarak bu duruma rastladım. Get()Hangi argümanın geçtiğinin tersini döndürecek simetrik yöntemler yazmak istedim . Bunun gibi bir şey:

class TwoWayRelationship<T1, T2>
{
    public T2 Get(T1 key) { /* ... */ }
    public T1 Get(T2 key) { /* ... */ }
}

Bir örnek oluşturursanız T1ve T2farklı türlerde iseniz, her şey iyi olur :

var r1 = new TwoWayRelationship<int, string>();
r1.Get(1);
r1.Get("a");

Ancak eğer T1ve T2aynı ise (ve muhtemelen biri diğerinin alt sınıfıysa), derleyici hatasıdır:

var r2 = new TwoWayRelationship<int, int>();
r2.Get(1);  // "The call is ambiguous..."

İlginçtir, ikinci durumda diğer tüm yöntemler hala kullanılabilir; sadece derleyici hatasına neden olan şimdi belirsiz olan yöntemi çağırır. İlginç bir durum, eğer biraz olası ve karanlıksa.


Yöntem aşırı yüklemesi karşıtları bunu sevecek ^ ^.
Christian Klauser

1
Bilmiyorum, bu bana çok mantıklı geliyor.
Scott Whitlock

10

C # Erişilebilirlik bilinmez


Aşağıdaki türetilmiş sınıf, temel sınıfından özel bir alana erişiyor ve derleyici diğer tarafa sessizce bakıyor:

public class Derived : Base
{
    public int BrokenAccess()
    {
        return base.m_basePrivateField;
    }
}

Alan gerçekten özeldir:

private int m_basePrivateField = 0;

Böyle bir kodu nasıl derleyeceğimizi tahmin etmek ister misiniz?

.

.

.

.

.

.

.

Cevap


İşin püf noktası Derivediç sınıf olarak ilan etmektir Base:

public class Base
{
    private int m_basePrivateField = 0;

    public class Derived : Base
    {
        public int BrokenAccess()
        {
            return base.m_basePrivateField;
        }
    }
}

İç sınıflara dış sınıf üyelerine tam erişim verilir. Bu durumda iç sınıf dış sınıftan da türetilir. Bu, özel üyelerin kapsüllenmesini "kırmamızı" sağlar.


Bu aslında iyi belgelenmiştir; msdn.microsoft.com/en-us/library/ms173120%28VS.80%29.aspx . Özellikle dış sınıf statikse, zaman zaman yararlı bir özellik olabilir.

Evet - elbette belgeleniyor. Ancak, çok az insan bu bulmacayı çözdü, bu yüzden harika bir trivia parçası olduğunu düşündüm.
Omer Mor

2
Bir iç sınıf sahibini
devralarak

Yine bir başka benzer (ve mükemmel derecede doğru) durum, bir nesnenin aynı tipteki başka bir nesnenin özel üyesine erişebilmesidir:class A { private int _i; public void foo(A other) { int res = other._i; } }
Olivier Jacot-Descombes

10

Bugün güzel bir şey buldum:

public class Base
{
   public virtual void Initialize(dynamic stuff) { 
   //...
   }
}
public class Derived:Base
{
   public override void Initialize(dynamic stuff) {
   base.Initialize(stuff);
   //...
   }
}

Bu derleme hatası atar.

'Initialize' yöntemine yapılan çağrının dinamik olarak gönderilmesi gerekir, ancak temel erişim ifadesinin bir parçası olması nedeniyle olamaz. Dinamik bağımsız değişkenleri yayınlamayı veya temel erişimi ortadan kaldırmayı düşünün.

Base.Initialize (nesne olarak şeyler) yazarsam; mükemmel çalışıyor, ancak bu burada "sihirli bir kelime" gibi görünüyor, tam olarak aynı olduğu için, her şey hala dinamik olarak alındı ​​...


8

Kullandığımız bir API'da, bir alan nesnesini döndüren yöntemler özel bir "boş nesne" döndürebilir. Bunun uygulanmasında, karşılaştırma operatörü ve Equals()yöntem true, karşılaştırılırsa döndürülecek şekilde geçersiz kılınır null.

Dolayısıyla, bu API'nın bir kullanıcısı aşağıdaki gibi bir koda sahip olabilir:

return test != null ? test : GetDefault();

ya da belki biraz daha ayrıntılı, şöyle:

if (test == null)
    return GetDefault();
return test;

Burada GetDefault(), kullanmak yerine kullanmak istediğimiz bazı varsayılan değerleri döndüren bir yöntemdir null. Sürpriz, ReSharper'ı kullanırken bana vurdu ve aşağıdakilerden birini yeniden yazmak için tavsiyeyi takip ederek:

return test ?? GetDefault();

Test nesnesi yerine uygun bir API dönen bir boş nesne ise null, kodun davranışı şimdilik boş birleştirme operatörü olarak, aslında çek değişti nullçalışmıyor, operator=ya da Equals().


1
Gerçekten ac # köşe durumda, ama bunu düşünen sevgili efendim?!?
Ray Booysen

Bu kod yalnızca null olabilecek türler değil mi? Bu nedenle ReSharper "??" kullanın. Ray'in dediği gibi, bunun bir köşe vakası olduğunu düşünmezdim; yoksa yanılıyor muyum?
Tony

1
Evet, türler null edilebilir - ve ayrıca bir NullObject var. Köşe bir durum ise bilmiyorum, ama en azından 'if (a! = Null) a; dönüş b; ' 'return a ?? ile aynı değil. b'. Kesinlikle çerçeve / API tasarımı ile ilgili bir sorun olduğunu kabul ediyorum - aşırı yükleme == null bir nesne üzerinde doğru dönmek kesinlikle iyi bir fikir değil!
Tor Livar

8

Bu garip durumu düşünün:

public interface MyInterface {
  void Method();
}
public class Base {
  public void Method() { }
}
public class Derived : Base, MyInterface { }

Eğer Baseve Derivedaynı derlemede ilan edilir, derleyici yapacak Base::Methodolsa, sanal ve (CIL olarak) mühürlü Basearabirimini uygulamaz.

Farklı derlemelerde Baseve varsa Derived, derleme derlenirken, Derivedderleyici diğer derlemeyi değiştirmez, bu nedenle çağrıyı delege edecek Derivedaçık bir uygulama olacak bir üye tanıtır .MyInterface::MethodBase::Method

Derleyici, arayüzle ilgili polimorfik gönderimi desteklemek için bunu yapmak zorundadır, yani bu yöntemi sanal yapmak zorundadır.


Gerçekten tuhaf geliyor. Daha sonra araştırmak zorunda
kalacak

@Jon Skeet: Ben C # rolleri için uygulama stratejileri araştırırken buldum . Bu konuda görüşlerinizi almak harika olurdu!
Jordão

7

Aşağıdakiler sadece eksik olduğum genel bilgi olabilir, ama ha. Bir süre önce, sanal özellikleri içeren bir hata vakamız vardı. Bağlamı biraz soyutlamak, aşağıdaki kodu göz önünde bulundurun ve belirtilen alana kesme noktası uygulayın:

class Program
{
    static void Main(string[] args)
    {
        Derived d = new Derived();
        d.Property = "AWESOME";
    }
}

class Base
{
    string _baseProp;
    public virtual string Property 
    { 
        get 
        {
            return "BASE_" + _baseProp;
        }
        set
        {
            _baseProp = value;
            //do work with the base property which might 
            //not be exposed to derived types
            //here
            Console.Out.WriteLine("_baseProp is BASE_" + value.ToString());
        }
    }
}

class Derived : Base
{
    string _prop;
    public override string Property 
    {
        get { return _prop; }
        set 
        { 
            _prop = value; 
            base.Property = value;
        } //<- put a breakpoint here then mouse over BaseProperty, 
          //   and then mouse over the base.Property call inside it.
    }

    public string BaseProperty { get { return base.Property; } private set { } }
}

İken Derivedeklerken nesne bağlamında, aynı davranışı elde edebilirsiniz base.Propertybir saat ya da yazmaya olarak base.PropertyQuickWatch içine.

Neler olduğunu anlamam için biraz zamanımı aldı. Sonunda Quickwatch tarafından aydınlandım. Quickwatch'a girip Derivedd nesnesini (veya nesnenin bağlamından this) basekeşfedip alanı seçerken , Quickwatch'ın üstündeki düzenleme alanı aşağıdaki yayını görüntüler:

((TestProject1.Base)(d))

Bu, taban bu şekilde değiştirilirse, çağrı

public string BaseProperty { get { return ((TestProject1.Base)(d)).Property; } private set { } }

Saatler, Quickwatch ve hata ayıklama fareyle üzerine gelme ipuçları için "AWESOME"kullanıldığında, "BASE_AWESOME"polimorfizm düşünüldüğünde bunun görüntülenmesi mantıklı olacaktır . Neden onu alçıya dönüştüreceğinden emin değilim, bir hipotez, callbu modüllerin bağlamında bulunmayabilir ve sadece callvirt.

Her neyse, bu işlevsellik açısından hiçbir şeyi değiştirmiyor Derived.BaseProperty, yine de gerçekten geri dönecek "BASE_AWESOME"ve bu yüzden bu, işimizdeki böceğimizin kökü değildi, sadece kafa karıştırıcı bir bileşen. Ancak, özellikle Baseprojenizde açığa çıkmamış, ancak 3. taraf DLL olarak atıfta bulunmuşsa, Devs sadece şunu söyleyerek , hata ayıklama oturumları sırasında bu gerçeğin farkında olmayacak geliştiricileri nasıl yanlış yönlendirebileceğini ilginç buldum :

"Oi, bekle .. ne? Omg DLL böyle, komik bir şey yapmak"


Bu özel bir şey değil, tam da bu işi geçersiz kılıyor.
yapılandırıcı

7

Bunun üstesinden gelmek oldukça zor. Begin / EndInvoke'u gerçekten destekleyen bir RealProxy uygulaması oluşturmaya çalışırken karşılaştım (korkunç hackler olmadan bunu imkansız kıldığınız için teşekkürler MS). Bu örnek temelde CLR'deki bir hatadır, BeginInvoke için yönetilmeyen kod yolu, RealProxy.PrivateInvoke (ve Invoke geçersiz kılmam) döndürme iletisinin bir IAsyncResult örneğini döndürdüğünü doğrulamaz. Bir kez iade edildiğinde, CLR inanılmaz derecede karışır ve alt kısımdaki testlerin gösterdiği gibi, neler olup bittiğine dair herhangi bir fikri kaybeder.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting.Proxies;
using System.Reflection;
using System.Runtime.Remoting.Messaging;

namespace BrokenProxy
{
    class NotAnIAsyncResult
    {
        public string SomeProperty { get; set; }
    }

    class BrokenProxy : RealProxy
    {
        private void HackFlags()
        {
            var flagsField = typeof(RealProxy).GetField("_flags", BindingFlags.NonPublic | BindingFlags.Instance);
            int val = (int)flagsField.GetValue(this);
            val |= 1; // 1 = RemotingProxy, check out System.Runtime.Remoting.Proxies.RealProxyFlags
            flagsField.SetValue(this, val);
        }

        public BrokenProxy(Type t)
            : base(t)
        {
            HackFlags();
        }

        public override IMessage Invoke(IMessage msg)
        {
            var naiar = new NotAnIAsyncResult();
            naiar.SomeProperty = "o noes";
            return new ReturnMessage(naiar, null, 0, null, (IMethodCallMessage)msg);
        }
    }

    interface IRandomInterface
    {
        int DoSomething();
    }

    class Program
    {
        static void Main(string[] args)
        {
            BrokenProxy bp = new BrokenProxy(typeof(IRandomInterface));
            var instance = (IRandomInterface)bp.GetTransparentProxy();
            Func<int> doSomethingDelegate = instance.DoSomething;
            IAsyncResult notAnIAsyncResult = doSomethingDelegate.BeginInvoke(null, null);

            var interfaces = notAnIAsyncResult.GetType().GetInterfaces();
            Console.WriteLine(!interfaces.Any() ? "No interfaces on notAnIAsyncResult" : "Interfaces");
            Console.WriteLine(notAnIAsyncResult is IAsyncResult); // Should be false, is it?!
            Console.WriteLine(((NotAnIAsyncResult)notAnIAsyncResult).SomeProperty);
            Console.WriteLine(((IAsyncResult)notAnIAsyncResult).IsCompleted); // No way this works.
        }
    }
}

Çıktı:

No interfaces on notAnIAsyncResult
True
o noes

Unhandled Exception: System.EntryPointNotFoundException: Entry point was not found.
   at System.IAsyncResult.get_IsCompleted()
   at BrokenProxy.Program.Main(String[] args) 

6

Bunun bir Windows Vista / 7 tuhaflığı mı yoksa bir .Net tuhaflığı mı olduğunu söyleyeceğinizden emin değilim ama bir süre kafamı kaşıyordu.

string filename = @"c:\program files\my folder\test.txt";
System.IO.File.WriteAllText(filename, "Hello world.");
bool exists = System.IO.File.Exists(filename); // returns true;
string text = System.IO.File.ReadAllText(filename); // Returns "Hello world."

Windows Vista / 7'de dosya aslında C:\Users\<username>\Virtual Store\Program Files\my folder\test.txt


2
Bu aslında bir manzara (7 değil, afaik) güvenlik geliştirmesidir. Ama havalı şey, dosyayı program dosyaları yolu ile okuyabilir ve açabilmenizdir, eğer explorer ile oraya bakarsanız hiçbir şey yoktur. Nihayet öğrenmeden önce bu bir müşteri beni neredeyse bir gün iş aldı.
Henri

Kesinlikle bir Windows 7 şey de. Onunla karşılaştığımda bunu kullanıyordum. Bunun arkasındaki mantığı anlıyorum ama anlamaya çalışmak hala sinir bozucuydu.
Spencer Ruport

Vista / Win 7'de (teknik olarak winXP) uygulamalar, teknik olarak kullanıcı verileri olarak Kullanıcılar-klasör alanında bir AppData klasörüne yazmalıdır. Uygulamalar yönetici ayrıcalıklarına sahip olmadıkça program dosyalarına / windows / system32 / vb. FAKAT! Yine de system32 / windows / etc'ye yazmayın :) Yukarıdaki kodu yönetici olarak çalıştırdıysanız (sağ tıklama> yönetici olarak çalıştır), teorik olarak program dosyaları uygulama klasörüne yazmalıdır.
Steve Syfuhs


6

C # derleyicisinin geçersiz CIL oluşturabileceğini hiç düşündünüz mü? Bunu çalıştırdığınızda şunları elde edersiniz TypeLoadException:

interface I<T> {
  T M(T p);
}
abstract class A<T> : I<T> {
  public abstract T M(T p);
}
abstract class B<T> : A<T>, I<int> {
  public override T M(T p) { return p; }
  public int M(int p) { return p * 2; }
}
class C : B<int> { }

class Program {
  static void Main(string[] args) {
    Console.WriteLine(new C().M(42));
  }
}

Nasıl olsa C # 4.0 derleyici ücretleri bilmiyorum.

EDIT : bu benim sistemden çıktı:

C:\Temp>type Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1 {

  interface I<T> {
    T M(T p);
  }
  abstract class A<T> : I<T> {
    public abstract T M(T p);
  }
  abstract class B<T> : A<T>, I<int> {
    public override T M(T p) { return p; }
    public int M(int p) { return p * 2; }
  }
  class C : B<int> { }

  class Program {
    static void Main(string[] args) {
      Console.WriteLine(new C().M(11));
    }
  }

}
C:\Temp>csc Program.cs
Microsoft (R) Visual C# 2008 Compiler version 3.5.30729.1
for Microsoft (R) .NET Framework version 3.5
Copyright (C) Microsoft Corporation. All rights reserved.


C:\Temp>Program

Unhandled Exception: System.TypeLoadException: Could not load type 'ConsoleAppli
cation1.C' from assembly 'Program, Version=0.0.0.0, Culture=neutral, PublicKeyTo
ken=null'.
   at ConsoleApplication1.Program.Main(String[] args)

C:\Temp>peverify Program.exe

Microsoft (R) .NET Framework PE Verifier.  Version  3.5.30729.1
Copyright (c) Microsoft Corporation.  All rights reserved.

[token  0x02000005] Type load failed.
[IL]: Error: [C:\Temp\Program.exe : ConsoleApplication1.Program::Main][offset 0x
00000001] Unable to resolve token.
2 Error(s) Verifying Program.exe

C:\Temp>ver

Microsoft Windows XP [Version 5.1.2600]

Benim için hem C # 3.5 derleyicisi hem de C # 4 derleyicisi ile çalışıyor ...
Jon Skeet

Sistemimde, çalışmıyor. Çıktıyı soruya yapıştıracağım.
Jordão

.NET 3.5'te benim için başarısız oldu (4.0'ı test etmek için zamanınız yok). Ve sorunu VB.NET koduyla çoğaltabilirim.
Mark Hurd

3

Kapakları işleme şekli C # hakkında gerçekten heyecan verici bir şey var.

Yığın değişken değerlerini kapama serbest değişkenine kopyalamak yerine, bu önişlemci büyüsünün değişkenin tüm oluşumlarını bir nesneye sarar ve böylece yığının dışına taşır - doğrudan yığına! :)

Sanırım, bu C # ML (dil yığını kopyalama AFAIK kullanır) daha işlevsel olarak tam (veya lambda-tam huh) dil yapar. C # 'da olduğu gibi F # da bu özelliğe sahiptir.

Bu bana çok zevk veriyor, teşekkürler MS millet!

Bu bir tuhaflık veya köşe durumu değil ... ama yığın tabanlı bir VM dilinden gerçekten beklenmedik bir şey :)


3

Uzun zaman önce sorduğum bir sorudan:

Koşullu operatör dolaylı olarak yayın yapamıyor mu?

Verilen:

Bool aBoolValue;

Nerede aBoolValue Doğru veya Yanlış atanır;

Aşağıdakiler derlenmeyecektir:

Byte aByteValue = aBoolValue ? 1 : 0;

Ancak bu:

Int anIntValue = aBoolValue ? 1 : 0;

Verilen cevap da oldukça iyi.


Her ne kadar ve not test it Ibu çalışacağından eminim: Byte aByteValue = aBoolValue? (Bayt) 1: (Bayt) 0; Veya: Byte aByteValue = (Byte) (aBoolValue? 1: 0);
Alex Pacurar

2
Evet, Alex, bu işe yarar. Anahtar örtük dökümde. 1 : 0tek başına Bayt'a değil, dolaylı olarak int'e uygulanır.
MPelletier

2

C # 'da kapsam belirleme bazen tuhaftır. Size bir örnek vereyim:

if (true)
{
   OleDbCommand command = SQLServer.CreateCommand();
}

OleDbCommand command = SQLServer.CreateCommand();

Komut yeniden bildirildiği için bu derlenemiyor? Bu bu şekilde çalışır neden olarak bazı ilgilenen varsayım vardır stackoverflow iplik ve blogumda .


34
Bunu özellikle tuhaf görmüyorum. Blogunuzda "kusursuz bir şekilde kod" dediğiniz şey, dil özelliklerine göre mükemmel şekilde yanlıştır . Size ediyorum bazı hayali bir dilde doğru olabilir gibi olmak C #, ama dil Spec C # geçersiz olduğunu çok açık.
Jon Skeet

7
Peki C / C ++ 'da geçerlidir. Ve C # olduğu için hala çalışmasını isterdim. Beni en çok etkileyen şey, derleyicinin bunu yapmasının bir nedeni olmaması. İç içe kapsam belirleme yapmak zor değil. Sanırım her şey en az sürpriz unsuruna geliyor. Spesifikasyonun bunu ve bunu söyleyebileceği anlamına gelir, ancak bu şekilde davranması tamamen mantıksızsa bu gerçekten çok yardımcı olmaz.
Anders Rune Jensen

6
C #! = C / C ++. Ayrıca cout << "Merhaba Dünya!" << endl; Console.WriteLine ("Merhaba Dünya!") yerine ;? Ayrıca mantıksız değil, sadece spec okuyun.
Kredns

9
Dilin çekirdeğinin bir parçası olan kapsam belirleme kurallarından bahsediyorum. Standart kütüphane hakkında konuşuyorsunuz. Ama şimdi, programlamaya başlamadan önce c # dilinin küçük özelliklerini okumalıyım.
Anders Rune Jensen

6
Eric Lippert aslında C #'ın son zamanlarda böyle tasarlanma nedenlerini açıkladı : blogs.msdn.com/ericlippert/archive/2009/11/02/… . Özet, değişikliklerin istenmeyen sonuçlara yol açma olasılığının düşük olmasıdır.
Helephant
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.