Boole ifadelerinde null koşullu işleçleri kullanmanın en iyi yolu


11

Şuna benzeyebilecek bir boole ifadesi yazıyorsunuz:

team.Category == "A Team" && team?.Manager?.IsVietnamVet

public class Manager
{
    public bool IsVietnamVet { get; set; }
}

public class Team
{
    public string Category { get; set; }

    public Manager Manager { get; set; }
}

... ve bir hata mesajı alıyorsunuz:

'&&' operatörü, 'bool' ve 'bool?' Türündeki işlenenlere uygulanamaz.

Bununla başa çıkmanın en iyi / en temiz yolu nedir?

  1. team.Category == "A Team" && (team?.Manager?.IsVietnamVet ?? false)

    Gerçekten okunabilir mi?

  2. team.Category == "A Team" && (team?.Manager?.IsVietnamVet).GetValueOrDefault()

    LINQ-to-Entities'de çalışmayabilir ...

  3. team.Category == "A Team" && team?.Manager?.IsVietnamVet == true

    if (condition == true)Hiç tereddüt etmeden gerçekten yazar mısın?

Başka seçenek var mı? Sonuçta yazmak daha mı iyi:

  1. team.Category == "A Team" && team.Manager != null && team.Manager.IsVietnamVet

if (! (String.IsNullOrEmpty (team.Manager) && koşulu)) ...
Snoop

1
@StevieV, en başından
beri böyle olmaktan bahsedildi

1
Koda daha dikkatli bir şekilde bakıldığında, sıfır koşullu kısmı team.Manager?.IsVietnamVet, yani teamzaten sıfır koşullu olmamalıdır , çünkü zaten olamaz null.
svick

2
"Tereddüt etmeden gerçekten (condition == true) yazar mısın?" Normal bir boole için, hayır, çünkü gereksiz. Ancak, boş bir boole için bu önemlidir. nullableBool == truetemelde test ediyor nullableBool != false && nullableBool != null(ve yararlı ve bu nedenle gereksiz kılan bu ikinci bölüm )
Flater

2
nullableBool == trueBir sarıcı oluşturmazsam kullanmaya başladım . == true@Flater'dan bahsedildiği gibi normal boolean kullanırken normal olarak yazmadığınız için okunabilir , bu nedenle değişkenin null edilebilir olduğunu gösterir. Ek olarak, @Fabio'dan bahsedildiği gibi birden fazla boş koşul kullanmamanız nedeniyle LINQ okunabilirliğini artırır.
Santhos

Yanıtlar:


4

Bu özel durumda, takip etmek akıllıca olur Demeter Hukuku yani

public class Team
{
    public bool IsManagerVietnamVet => Manager?.IsVietnamVet ?? false;
}    

Daha genel olarak, bir boole ifadesi karmaşık veya çirkin ise, ifadeyi (veya bir kısmını) ayrı bir ifadeye bölemeyeceğinizi söyleyecek hiçbir şey yoktur:

bool isVietnamVet = Manager?.IsVietnamVet ?? false;

if (team.Category == "A Team" && isVietnamVet)

Hata ayıklayıcıdaki koddan geçerken, boolbiraz fareyle üzerine gelindiğinde tasarruf etmek için ayrıntılı koşulların tek bir pakette toplanması genellikle daha iyidir; aslında, her şeyi bir booldeğişkene koymak daha hoş olabilir .

bool isVietnamVetAndCategoryA = (team.Category == "A Team"
    && Manager?.IsVietnamVet ?? false);

if (isVietnamVetAndCategoryA)

veya LINQ ile:

var wibble = from flight in airport
             from passenger in flight.manifest
             let isOnPlane = 
                 (flight.FinishedBoarding && passenger.Flight == flight.FlightNumber)
             where !isOnPlane
             select passenger;

Sanırım çoğunlukla böyle bir çözüme yöneliyorum.
Santhos

1
Birkaç satır kaydetmek için yeni C # sözdizimi: genel bool IsManagerVietnamVet => (team.Category == "") && (team.Manager? .IsVietnamVet ?? false);
Graham

Uzun sürenin a && b && c &&...ardışık olarak yürütüldüğünü ve bir öncekinin bile bir sonraki yürütüldüğünü unutmayın false. Bu yüzden insanlar genellikle başlangıçta en hızlı şekilde koyarlar. Eşyaları ayrı bir bool-
var'a

@jitbit Daha çok sürdürülebilirlikle ilgili. Bahsettiğiniz gibi mikro optimizasyonlar genellikle gereksizdir - performans bir sorun olarak tanımlanmadıkça ve profil oluşturma, böyle değişiklikler yapmanın gözle görülür bir etkisi olacağını göstermedikçe endişelenmeye değmez.
Ben Cottrell

@BenCottrell IsManagerVietnamVetÖzellik bir veritabanında kontrol etmeye giderse ben buna bir "mikro" optimizasyon
denir

3

Ben seçeneği 3 (yani düşünüyorum == true) bir o teste basit yoludur, bool?olduğu trueo ne yaptığını hakkında çok açık, çünkü.

Çoğu kod x == truemantıklı değil, çünkü aynı x, ama bu burada geçerli değil, bu yüzden == trueçok kafa karıştırıcı olmayacağını düşünüyorum .


1
Boş koşullu operatörü kullanmak istersek, bu kesinlikle gitmek için bir yol olacağını düşünüyorum, çünkü aynı zamanda linq güvenlidir. Soru, okunabilirliğin iyi olup olmadığıdır. Benim açımdan, tercih 3 ve opt 4 arasındadır ve okunabilirlik nedeni için 3'ten 4'ü seçerdim, ayrıca programcının niyeti biraz daha net görünüyor. Ben Cottrell'in cevabını doğru olarak işaretledim çünkü bu yaklaşımı biraz daha seviyorum. İki cevabı işaretleyebilseydim yapardım.
Santhos

1
@Santhos - yeniden "programcının niyeti biraz daha açık görünüyor". IMHO, bu, bir programcının ilk kez kafanın karışacağını gördüğü bir durumdur a?.b == true, ancak ne yaptığını kavradığında, != nullkarmaşık bir ifadenin ortasında test yapmaktan çok daha hoş bir deyim haline gelir . İçin aynı a?.b ?? falseEğer bir türüyle uğraşan olsaydı ne yazarsınız eşleştiği için, en popüler çözüm olarak ilgi çekmektedir görünüyor ki, diğer [boolean daha ben boolean için böyle değil gerçi; benim için doğal olarak okumuyor; Tercih ederim == true].
ToolmakerSteve

3

Ben Cottrell'in cevabı üzerine genişleyen "Boş Nesne" düzeni size daha fazla yardımcı olabilir.

Bir nullekibi / menajeri geri vermek yerine, anlamlı alternatif uygulamalar elde edin ITeamve IManagerarayüz oluşturun:

public class NoManager : IManager
{
    public bool IsVietnamVet => false;
}

public class NoTeam : ITeam
{
    public bool ManagedByVietnamVet => false;

    public IManager Manager => new NoManager();
}

Sonra aniden team.ManagedByVietnamVetgüvenli bir şekilde yapabilirsiniz .

Bu elbette yukarı akış sağlayıcısının teamsıfırdan güvenli olmasına bağlıdır - ancak bu uygun testlerle sağlanabilir.


-4

Kullanabileceğiniz basit bir sınıf yazdım:

 public class MyBool 
    {
        public bool? Value { get; set; }

        public MyBool(bool b)
        {
            Value = b;
        }

        public MyBool(bool? b)
        {
            Value = b;
        }

        public static implicit operator bool(MyBool m)
        {
            return m?.Value ?? false;
        }

        public static implicit operator bool?(MyBool m)
        {
            return m?.Value;
        }

        public static implicit operator MyBool(bool m)
        {
            return new MyBool(m);
        }

        public static implicit operator MyBool(bool? m)
        {
            return new MyBool(m);
        }

        public override string ToString()
        {
            return Value.ToString();
        }
    }

Elbette, özel bir tür kullanmak güvenilirse. Her MyBoolikisini boolve ile karşılaştırabilirsiniz Nullable<bool>.


1
Bu site, belirli kod parçalarının nasıl çalışacağından ziyade yazılım tasarımı hakkında sorular içindir, bu yüzden bunun en iyi çözüm olduğuna inanıyorsanız, cevabınız bunun gibi bir sınıfın neden mümkün olan en iyi çözüm olduğuna inandığınıza odaklanmalıdır. uygulamak için tam kod gerekir.
Ixrec
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.