C # 'daki Guid.Empty parametresini nasıl varsayılan olarak ayarlayabilirim?


178

Söylemek istiyorum:

public void Problem(Guid optional = Guid.Empty)
{
}

Ancak derleyici Guid.Empty'nin derleme zamanı sabiti olmadığından şikayet ediyor.

API değiştirmek istemiyorum gibi kullanamıyorum:

 Nullable<Guid>


Geçiş nesi yanlış Nullable<Guid> optional = null(daha tersely ya Guid? optional = null)? Şu anda kendisine iletilen tüm Kılavuzlar, herhangi bir kod değişikliği gerekmeden zorlanacaktır.
NH.

Yanıtlar:


235

Çözüm

Bunun new Guid()yerine kullanabilirsiniz

public void Problem(Guid optional = new Guid())
{
  // when called without parameters this will be true
  var guidIsEmpty = optional == Guid.Empty;
}

Ayrıca kullanabilirsiniz default(Guid)

default(Guid)ayrıca tam olarak çalışacaktır new Guid().

Guid, başvuru türü olmayan bir değer türü olduğundan, örneğin, default(Guid)eşit değildir null, bunun yerine varsayılan yapıcı çağrılmasına eşittir.

Bu şu anlama gelir:

public void Problem(Guid optional = default(Guid))
{
  // when called without parameters this will be true
  var guidIsEmpty = optional == Guid.Empty;
}

Orijinal örnekle tamamen aynı.

açıklama

Neden Guid.Emptyçalışmadı?

Hatayı almanızın nedeni Emptyşu şekilde tanımlanmasıdır:

public static readonly Guid Empty;

Yani, bu bir değişken değil, (olarak tanımlanan bir sabittir static readonlydeğil const). Derleyici, yöntem parametreleri varsayılan değerleri olarak yalnızca derleyici tarafından bilinen değerlere sahip olabilir (yalnızca çalışma zamanı için bilinmez).

Temel neden, örneğin aksine const, hiçbirine sahip structolamamanızdır enum. Eğer denerseniz, derlenmeyecektir.

Nedeni bir kez daha structilkel bir tip olmaması.
.NET'teki tüm ilkel türlerin listesi için bkz. Http://msdn.microsoft.com/en-gb/library/system.typecode.aspx
( enumgenellikle intilkel olan devralmayı unutmayın )

Ama new Guid()sabit de değil!

Sabit olması gerektiğini söylemiyorum. Derleme zamanında karar verilebilecek bir şeye ihtiyacı vardır. Emptybir alandır, bu nedenle değeri derleme zamanında bilinmez (yalnızca çalışma süresinin en başında).

Varsayılan parametre değeri derleme zamanında bilinmelidir, bu bir constdeğer olabilir veya derleme zamanında değeri bilinen bir C # özelliği kullanılarak tanımlanmış bir şey ( default(Guid)veya new Guid()yapıcıyı structdeğiştiremediğiniz için s derleme zamanında belirlenir struct) kodu).

Sağlayabilir defaultveya newkolayca sağlayabilirsiniz, ancak const(ilkel bir tür veya enumyukarıda açıklandığı gibi değil) sağlayamazsınız . Yani, yine, isteğe bağlı parametrenin kendisinin sabit, ancak derleyici bilinen bir değere ihtiyacı olduğunu söylemez.


5
new Guid()Örneğin, normal bir sabit ifadeye ihtiyaç duymaz - örneğin sabit bir ifade değildir. C # spec, sabitler dahil ancak bunlarla sınırlı olmamak üzere izin verilenleri oldukça açık bir şekilde tanımlar . (Daha açıkçası, etkili olan C # Spec açısından değil sadece bir "sabit ifade", bir derleme zamanı sabiti).
Jon Skeet

3
Cevabımda Açıklama bölümünü okuyun . Bu bölüme cevap vermek için eklendi.
Meligy

Güzel açıklama.Teşekkürler!
Daryl

Sadece defaultbugünlerde kullanabilirsiniz :)
Joshit

151

Guid.Emptyeşittir new Guid(), eşittir default(Guid). Böylece şunları kullanabilirsiniz:

public void Problem(Guid optional = default(Guid))

veya

public void Problem(Guid optional = new Guid())

Not new Foo()değerdir sadece zaman uygulanabilir:

  • Gerçekten parametresiz kurucu diyorsun
  • Foo bir değer türüdür

Başka bir deyişle, derleyici bunun gerçekten tür için varsayılan değer olduğunu bildiğinde :)

(İlginçtir, ben% 99,9 değilim emin olmaz herhangi bir özel çağrı new Foo()oluşturmuş olduğunuz yapıcı. Sen C # bir değer türü böyle bir yapıcı oluşturamıyor, ancak yapabilirsiniz IL içinde yapabilirsiniz.)

default(Foo)Seçeneği herhangi bir tür için kullanabilirsiniz .


Derleyici hata mesajı neden bana bunu söylemiyor, şikayetçi Guid.Empty durumunu kontrol edebilir ve daha yararlı bir mesaj verebilir.
Ian Ringrose

4
@Ian Ringrose: Dürüst olmak gerekirse derleyicinin genel olarak türe özgü mesajları olması gerektiğini düşünmüyorum.
Jon Skeet

2
Bir parametrenin varsayılan olarak yeni bir nesneye ayarlanması, yöntem PHP'de her çağrıldığında yeni bir nesne oluşturur; ancak Python'daki programın tamamı için yalnızca bir nesne oluşturur . Gerçekten, bunun Python'un çok az tasarım kusurundan biri olduğunu düşünüyorum . Biraz sevindim C # (ve VB.Net) sadece varsayılan parametrelerde yeni nesneler izin vermeyerek bu sorunu önledi ... gerçi PHP bu gerçekten güzel olduğu zamanlar olsa da.
BlueRaja - Danny Pflughoeft

1
aynı şeyin ASP.NET MVC denetleyici eyleminde çalışmamasının nedeni ne olabilir? Diğer tüm isteğe bağlı parametreler (int, string) çalışır ancak GUID için çalışmaz, "/ 'Uygulamasında Sunucu Hatası. Parametreler sözlüğü, boş olmayan türdeki' SystemIG 'parametresi için boş bir girdi içeriyor. System.Guid '.. "Kod her iki spesifikasyonla (varsayılan (Guid) ve yeni Guid ()) iyi derlenir, ancak bu hatayı yayınlar.
kısrak

@mare: Bilmiyorum, korkuyorum. Başka bir seçenek de Nullable<Guid>potansiyel olarak kullanmak olacaktır .
Jon Skeet

18

Kullanamaz mısınız:

default ( Guid ) ?


1
Hayır. Operator '??' cannot be applied to operands of type 'System.Guid' and 'System.Guid'
özyinelemeli

4
Üzgünüm, demek istemedim ?? bir operatör olarak ama üzerinde durulan bir soru işareti olarak - düzenleyeceğim!
Nick

9

Kabul edilen yanıt ASP.NET MVC'de çalışmaz ve bu çalışma zamanı hatasına neden olur:

[ArgumentException: The parameters dictionary contains a null entry for parameter 'optional' of non-nullable type 'System.Guid' for method 'System.Web.Mvc.ActionResult Problem(System.Guid)' ....

Bunun yerine, aşağıdakileri yapabilirsiniz:

public void Problem(Guid? optional)
{
    if (optional == null)
    {
        optional = new Guid();
    }
}

Ben aşağı-oylama nedenini bakın: API Nullable <Guid> kullanmak değiştirilemez bu soruyu belirliyorsa - Fuar yeterince
Majix

Boş bir Guid değeriyle "isteğe bağlı" parametresini açıkça atamak istemiyorsanız, bunun Guid türünde isteğe bağlı bir parametre tanımlamanın en doğal yolu olduğunu düşünüyorum.
Gonzalo Méndez,

4

Derleyici oldukça doğrudur; Guid.Emptyderleme zamanı sabiti değildir. Böyle bir yöntem aşırı yüklemesi yapmayı deneyebilirsiniz:

public void Problem()
{
    Problem(Guid.Empty);
}

Ben API değiştirmek istemediğini söyledi, evcilleştirmek için çalışıyorum yöntemi 10 parms overe var!
Ian Ringrose

@Ian Ringrose, Guid x = default(Guid)çözüm olarak kabul etsem de, başka bir işlev aşırı yüklemesi eklemenin, isteğe bağlı bir argüman eklemekten daha fazla API'yi karmaşık hale getirmediğini unutmayın. Gerçekten de isteğe bağlı bir argüman böyle yapar.
tenfour

@ yoğun, 10 isteğe bağlı parms ile aynı şeyi yapmak için birçok yeni aşırı yük olması gerekir!
Ian Ringrose

Ondan fazla parametre gerektiren bir genel işleviniz varsa, isteğe bağlı olarak tek bir argüman oluşturmak gerçekten bir çözüm değildir ... Ayrıca, orijinal soruya geri dönersek, gerçekten " API "(ve on dörtlü gibi, açık bir aşırı yük ile isteğe bağlı bir argüman arasındaki fark pratikte minimumdur), ancak parametre listesinin bu tür bir canavar olduğu sorusundan söz edilmemektedir.
CVn

Aslında, bu soruna mükemmel bir cevap.
PKD
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.