C #: 'is' anahtar kelimesi ve Not


288

Bu aptalca bir soru, ama bir şey belirli bir tür olup olmadığını kontrol etmek için bu kodu kullanabilirsiniz ...

if (child is IContainer) { //....

"NOT" örneğini kontrol etmenin daha zarif bir yolu var mı?

if (!(child is IContainer)) { //A little ugly... silly, yes I know...

//these don't work :)
if (child !is IContainer) {
if (child isnt IContainer) { 
if (child aint IContainer) { 
if (child isnotafreaking IContainer) { 

Evet, evet ... aptalca bir soru ...

Kodun neye benzediğine dair bir soru olduğundan , bir yöntemin başlangıcında basit bir dönüş.

public void Update(DocumentPart part) {
    part.Update();
    if (!(DocumentPart is IContainer)) { return; }
    foreach(DocumentPart child in ((IContainer)part).Children) {
       //...etc...

105
Ben şahsen "çocuk korkmuyor ..." gibi. Bu anahtar kelimeyi C # 5
Joseph

Bunu kullanacağın durumu bilmek isterim? Bu kodun "else" kısmı neye benziyor ve testi tersine çeviremez misiniz? Kodunuz "çocuk bir IContainer değilse o zaman istisnalar atmak" veya "çocuk bir IContainer değilse" belki de bir IFoo öyleyse bundan sonra deneyeceğim "diyorsa, o zaman zımni başka bir ifade yok mu? Muhtemelen bir şey özlüyorum.
Martin Peck

1
@MartinPeck, başka bir madde olmayabilir. Bunu aramamın nedeni bu.
Joshua Walsh

@MartinPeck burada bir örnek: if (!(argument is MapsControlViewModel vm)) { return; }- Eğer if ters olabilir ve whoooole yöntemin geri kalanı if köşeli parantez içine koymak, ama sonra yöntemin sonunda çok sayıda kapanış parantez ile Noel ağacı kodu alırdım. Bu daha az okunabilir.
ANeves

belki genel olarak ihtiyacımız olan ifnotifadelerdir
Dave Cousineau

Yanıtlar:


301
if(!(child is IContainer))

tek operatördür ( IsNotoperatör yoktur ).

Bunu yapan bir uzantı yöntemi oluşturabilirsiniz:

public static bool IsA<T>(this object obj) {
    return obj is T;
}

ve daha sonra aşağıdakileri yapmak için kullanın:

if (!child.IsA<IContainer>())

Ve temanızı takip edebilirsiniz:

public static bool IsNotAFreaking<T>(this object obj) {
    return !(obj is T);
}

if (child.IsNotAFreaking<IContainer>()) { // ...

Güncelleme (OP'nin kod snippet'ini dikkate alarak):

Aslında değeri daha sonra yayınladığınız için asbunun yerine şunu kullanabilirsiniz :

public void Update(DocumentPart part) {
    part.Update();
    IContainer containerPart = part as IContainer;
    if(containerPart == null) return;
    foreach(DocumentPart child in containerPart.Children) { // omit the cast.
       //...etc...

1
ck: Yani operatörler anlamında bir IsNotşey yok .
Mehrdad Afshari

5
Evet. Belli olmasa şaka yapıyorum.
Mehrdad Afshari

111

Bunu şu şekilde yapabilirsiniz:

object a = new StreamWriter("c:\\temp\\test.txt");

if (a is TextReader == false)
{
   Console.WriteLine("failed");
}

2
@Frank - evet, false karşılaştırabilirsiniz bir boolean verir anahtar kelime olduğunu
CJK

32
@Frank çalışıyor çünkü isgöreceli olarak daha yüksek önceliğe sahiptir ==. Kullanamamanızın tek nedeni !x is f, önceliğinden daha az önceliğe sahip olmasıdır !.
Mehrdad Afshari

Bunu beğendim, ancak bir değişkeni getirirken doğru olması gerektiği gibi görünmüyor. if (a is TextReader reader == false)"gerekir" çalışır, ancak değişkenin başlatılmamış olabileceğini söyleyerek değişkeni gerçek yolda kullanmanıza izin vermez.
Dave Cousineau

@DaveCousineau - Normalde, tanıtılan değişkeni kullanmak istediğinizde bir değişkeni yazar ve tanımlarsınız. Değişken nasıl daktilo başarısız olursa yararlı olacağını emin değilim. (Feragat - Ben kötü bir şekilde adlandırılmış ve kötü bir kod kokusu outparametreleri kullanarak hem de "Desen Eşleştirme" özelliği bulmak
StingyJack

@StingyJack, gerçek yolda değişkenin başlatılmamış olduğu düşünülen bir çeşit aksaklık vardır . if (a is TextReader reader == true)değişkenin başlatılmadığını düşündüğünüzü söyleseniz bile .
Dave Cousineau

11

Neden sadece başkasını kullanmıyorsun?

if (child is IContainer)
{
  //
}
else
{
  // Do what you want here
}

Düzgün tanıdık ve basit mi?


3
Bunda yanlış bir şey yok - bu sadece bir nitpick sorusu. Bir şey belirli bir tür değilse hemen bir işlevden çıkmak istedim. Bunu sonsuza kadar yaptım (! (Çocuk bir şeydir)), ama daha iyi bir yol olmadığından emin olacağımı düşündüm.
Hugoware

1
Söz konusu örnek kodla, bu parantez boş ise anlamına gelir. Bu mantıklı bir alternatif gibi görünmüyor.
ANeves

9

Eğer buna sahip yolu iyi ama sen olabilir yapmak için uzatma yöntemleri kümesi oluşturmak " 'DEĞİL' örneğin kontrol etmek daha zarif bir şekilde."

public static bool Is<T>(this object myObject)
{
    return (myObject is T);
}

public static bool IsNot<T>(this object myObject)
{
    return !(myObject is T);
}

Sonra şunu yazabilirsiniz:

if (child.IsNot<IContainer>())
{
    // child is not an IContainer
}

7

Bu henüz bahsedilmedi. Çalışıyor ve bence kullanmaktan daha iyi görünüyor!(child is IContainer)

if (part is IContainer is false)
{
    return;
}

issözdizimi expr is constant :; burada ifade, değerlendirilecek ifadedir ve sabit, test edilecek değerdir.


3
Benzer şekilde yapabilirsin if (part as IContainer is null). Dürüst olmak gerekirse hangisinin daha iyi olduğundan emin değilim.
Flynn1179

5

Çirkin? Katılmıyorum. Diğer tek yol (kişisel olarak bu "çirkin" olduğunu düşünüyorum):

var obj = child as IContainer;
if(obj == null)
{
   //child "aint" IContainer
}

@Mehrdad - Nullable? çalışmasını sağlar, bunun kullanılması gerekmez. Bu sadece daha çirkin bir yol örneği.
stevehipwell

@ Steveo3000: Evet, ama açıkça söylemelisiniz? olduğu ashüküm. obj as inther zaman derleme zamanı hatasıdır.
Mehrdad Afshari

@Mehrdad - Kabul etti, BFree yazılarını bunu yansıtacak şekilde düzenleyebilir. Bize 'obj olarak int mi veriyorsunuz?'
stevehipwell

@ Stevo3000: Bununla ilgili bir şeylerin yanlış olduğunu düşünmüyorum. IContainer, değer türü yerine bir arabirim gibi hissediyor. Sadece değer türüne dikkat gerektirdiğini ve her zaman isformun doğrudan bir çevirisi olmadığını belirtmek istedim .
Mehrdad Afshari

isteğe bağlı olarak, değer türleri ve başvuru türleriyle ilgilenecekse (obj == varsayılan (IContainer)) yapabilirsiniz
Joseph

3

isEğer her şeyi yapabilir, böylece bir boolean sonuca operatör değerlendirir, aksi takdirde bir bool yapmak mümkün olacaktır. Olumsuzlaştırmak için !operatörü kullanın . Neden sadece bunun için farklı bir operatör olmasını istesin ki?


5
Farklı bir operatör değil. Ekstra parens setini bırakmama izin verecek bir anahtar kelime olup olmadığını merak ediyordum. Bu büyük bir nit-pick, ama merak ettim.
Hugoware

Tamam anladım. Örneklerinizden, yeni ve özel bir operatör aradığınız izlenimini edindim.
Brian Rasmussen

Böyle bir özel operatöre sahip olmanın kötü olduğunu düşünüyorum, çünkü bu şekilde olacağız (zaten bu ve açıkladı) ve başka bir op'umuz olsaydı, o zaman aynı şeyi elde etmenin iki yolu var, kafa karıştırıcı olabilir.
BuddhiP

3

Genişletme yöntemi IsNot<T>, sözdizimini genişletmenin güzel bir yoludur. Aklında tut

var container = child as IContainer;
if(container != null)
{
  // do something w/ contianer
}

gibi bir şey yapmaktan daha iyi performans gösterir

if(child is IContainer)
{
  var container = child as IContainer;
  // do something w/ container
}

Sizin durumunuzda, yöntemden döndüğünüzde önemli değil. Başka bir deyişle, hem tür kontrolünü, hem de hemen sonra tür dönüşümünü yapmamaya dikkat edin.


3

Bu parantez sorunundan kaçınmasa da, Google üzerinden buraya gelen insanlar uğruna, kodunuzun geri kalanını biraz daha temiz hale getirmek için daha yeni sözdiziminin (C # 7'den itibaren) mevcut olduğu belirtilmelidir:

if (!(DocumentPart is IContainer container)) { return; }
foreach(DocumentPart child in container.Children) {
    ...

Bu, çift döküm, null-kontrol ve null olabileceği kapsamlarda mevcut bir değişkene sahip olmayı önler.


2

IS operatörü normalde en iyi yol olsa da, bazı durumlarda kullanabileceğiniz bir alternatif vardır. As operatörünü kullanabilir ve null için test edebilirsiniz.

MyClass mc = foo as MyClass;
if ( mc == null ) { }
else {}

2

C 9. mantıksal desenleri içerecektir (NET 5 ile tahliye edilecek) and, orve notbizi daha zarif bunu yazmak olanak veren:

if (child is not IContainer) { ... }

Benzer şekilde, bu desen null olup olmadığını kontrol etmek için kullanılabilir:

if (child is not null) { ... }

Bu değişikliği izleyen Github sorunu hakkında daha fazla bilgi bulabilirsiniz .


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.