Atmalar - C# Ile İlgili Temel Bilgiler

Atmalar, uygulama kodunda kasıtlı olarak kullanılmayan yer tutucu değişkenlerdir. Atmalar atanmamış değişkenlere eşdeğerdir; bir değeri yoktur. Atma, amacı derleyiciye ve kodunuzu okuyan diğer kişilere iletir: İfadenin sonucunu yoksaymak niyetindesiniz. Bir ifadenin sonucunu, bir tanımlama grubu ifadesinin bir veya daha fazla üyesini, out bir yöntemin parametresini veya desen eşleştirme ifadesinin hedefini yoksaymak isteyebilirsiniz.

Atmalar kodunuzun amacını net hale getirir. Atma, kodumuzun hiçbir zaman değişkenini kullanmadığını gösterir. Okunabilirliğini ve sürdürülebilirliğini geliştirir.

Bir değişkenin, adı olarak alt çizgi (_) atayarak atıldığını belirtirsiniz. Örneğin, aşağıdaki yöntem çağrısı, birinci ve ikinci değerlerin atıldığı bir tanımlama grubu döndürür. area , tarafından GetCityInformationdöndürülen üçüncü bileşene ayarlanmış daha önce bildirilen bir değişkendir:

(_, _, area) = city.GetCityInformation(cityName);

Bir lambda ifadesinin kullanılmayan giriş parametrelerini belirtmek için atmaları kullanabilirsiniz. Daha fazla bilgi için Lambda ifadeleri makalesinin Lambda ifadesinin giriş parametreleri bölümüne bakın.

Geçerli bir atma olduğunda _ , değerini almaya veya atama işleminde kullanmaya çalışmak, "'_' adı geçerli bağlamda yok" derleyici hatası CS0103 oluşturur. Bu hatanın nedeni _ , bir değer atanmaması ve depolama konumu bile atanmamasıdır. Gerçek bir değişkense, önceki örnekte olduğu gibi birden fazla değeri atamazdınız.

Tanımlama grubu ve nesne yapısı

Atmalar, uygulama kodunuz bazı tanımlama grubu öğelerini kullandığında ancak diğerlerini yoksaydığında tanımlama kümeleri ile çalışırken yararlıdır. Örneğin, aşağıdaki QueryCityDataForYears yöntem bir şehir, onun alanı, bir yıl, o yıl için şehir nüfusu, ikinci yıl ve o ikinci yıl için şehrin nüfusu ile bir tanımlama grubu döndürür. Örnekte, bu iki yıl arasındaki nüfus değişikliği gösterilmektedir. Tanımlama grubundaki verilerden şehir alanıyla ilgili bilgimiz yok ve tasarım zamanında şehir adını ve iki tarihi biliyoruz. Sonuç olarak, yalnızca tanımlama grubunda depolanan iki popülasyon değeriyle ilgileniyoruz ve kalan değerlerini atılmış olarak işleyebiliriz.

var (_, _, _, pop1, _, pop2) = QueryCityDataForYears("New York City", 1960, 2010);

Console.WriteLine($"Population change, 1960 to 2010: {pop2 - pop1:N0}");

static (string, double, int, int, int, int) QueryCityDataForYears(string name, int year1, int year2)
{
    int population1 = 0, population2 = 0;
    double area = 0;

    if (name == "New York City")
    {
        area = 468.48;
        if (year1 == 1960)
        {
            population1 = 7781984;
        }
        if (year2 == 2010)
        {
            population2 = 8175133;
        }
        return (name, area, year1, population1, year2, population2);
    }

    return ("", 0, 0, 0, 0, 0);
}
// The example displays the following output:
//      Population change, 1960 to 2010: 393,149

Demetleri atmalarla yapılandırma hakkında daha fazla bilgi için bkz . Tanımlama demetlerini ve diğer türleri yapılandırma.

Deconstruct Sınıfın, yapının veya arabirimin yöntemi, bir nesneden belirli bir veri kümesini almanıza ve kaldırmanıza da olanak tanır. Kaldırılan değerlerin yalnızca bir alt kümesiyle çalışmak istediğinizde atmaları kullanabilirsiniz. Aşağıdaki örnek, bir Person nesneyi dört dizeye (ad ve soyadı, şehir ve eyalet) ayırır, ancak soyadını ve eyaleti atar.

using System;

namespace Discards
{
    public class Person
    {
        public string FirstName { get; set; }
        public string MiddleName { get; set; }
        public string LastName { get; set; }
        public string City { get; set; }
        public string State { get; set; }

        public Person(string fname, string mname, string lname,
                      string cityName, string stateName)
        {
            FirstName = fname;
            MiddleName = mname;
            LastName = lname;
            City = cityName;
            State = stateName;
        }

        // Return the first and last name.
        public void Deconstruct(out string fname, out string lname)
        {
            fname = FirstName;
            lname = LastName;
        }

        public void Deconstruct(out string fname, out string mname, out string lname)
        {
            fname = FirstName;
            mname = MiddleName;
            lname = LastName;
        }

        public void Deconstruct(out string fname, out string lname,
                                out string city, out string state)
        {
            fname = FirstName;
            lname = LastName;
            city = City;
            state = State;
        }
    }
    class Example
    {
        public static void Main()
        {
            var p = new Person("John", "Quincy", "Adams", "Boston", "MA");

            // Deconstruct the person object.
            var (fName, _, city, _) = p;
            Console.WriteLine($"Hello {fName} of {city}!");
            // The example displays the following output:
            //      Hello John of Boston!
        }
    }
}

Atmalarla kullanıcı tanımlı türlerin yapısını kaldırma hakkında daha fazla bilgi için bkz . Tanımlama demetlerini ve diğer türleri yapılandırma.

ile desen eşleştirme switch

Atma deseni, switch ifadesiyle eşleşen desende kullanılabilir. dahil olmak üzere nullher ifade her zaman atma deseni ile eşleşir.

Aşağıdaki örnek, bir ProvidesFormatInfo nesnenin bir switch uygulama sağlayıp sağlamadığını belirlemek ve nesnenin nullolup olmadığını test etmek için bir ifade kullanan bir IFormatProvider yöntemi tanımlar. Ayrıca, başka herhangi bir türdeki null olmayan nesneleri işlemek için atma desenini kullanır.

object?[] objects = [CultureInfo.CurrentCulture,
                   CultureInfo.CurrentCulture.DateTimeFormat,
                   CultureInfo.CurrentCulture.NumberFormat,
                   new ArgumentException(), null];
foreach (var obj in objects)
    ProvidesFormatInfo(obj);

static void ProvidesFormatInfo(object? obj) =>
    Console.WriteLine(obj switch
    {
        IFormatProvider fmt => $"{fmt.GetType()} object",
        null => "A null object reference: Its use could result in a NullReferenceException",
        _ => "Some object type without format information"
    });
// The example displays the following output:
//    System.Globalization.CultureInfo object
//    System.Globalization.DateTimeFormatInfo object
//    System.Globalization.NumberFormatInfo object
//    Some object type without format information
//    A null object reference: Its use could result in a NullReferenceException

Parametrelerle out yöntemlere çağrılar

Kullanıcı tanımlı bir türü (bir sınıf, yapı veya arabirimin örneği) yok etmek için yöntemini çağırırken Deconstruct bağımsız out değişkenlerin değerlerini atabilirsiniz. Ancak bir parametre ile herhangi bir out yöntemi çağırırken bağımsız değişkenlerin out değerini de atabilirsiniz.

Aşağıdaki örnek, bir tarihin dize gösteriminin geçerli kültürde geçerli olup olmadığını belirlemek için DateTime.TryParse(String, out DateTime) yöntemini çağırır. Örnek yalnızca tarih dizesini doğrulamayla ilgili olduğundan ve tarihi ayıklamak için ayrıştırmayla ilgilenmediğinden, out yöntemin bağımsız değişkeni atılır.

string[] dateStrings = ["05/01/2018 14:57:32.8", "2018-05-01 14:57:32.8",
                      "2018-05-01T14:57:32.8375298-04:00", "5/01/2018",
                      "5/01/2018 14:57:32.80 -07:00",
                      "1 May 2018 2:57:32.8 PM", "16-05-2018 1:00:32 PM",
                      "Fri, 15 May 2018 20:10:57 GMT"];
foreach (string dateString in dateStrings)
{
    if (DateTime.TryParse(dateString, out _))
        Console.WriteLine($"'{dateString}': valid");
    else
        Console.WriteLine($"'{dateString}': invalid");
}
// The example displays output like the following:
//       '05/01/2018 14:57:32.8': valid
//       '2018-05-01 14:57:32.8': valid
//       '2018-05-01T14:57:32.8375298-04:00': valid
//       '5/01/2018': valid
//       '5/01/2018 14:57:32.80 -07:00': valid
//       '1 May 2018 2:57:32.8 PM': valid
//       '16-05-2018 1:00:32 PM': invalid
//       'Fri, 15 May 2018 20:10:57 GMT': invalid

Tek başına atma

Yoksaymayı seçtiğiniz herhangi bir değişkeni belirtmek için tek başına atma kullanabilirsiniz. Tipik kullanımlardan biri, bir bağımsız değişkenin null olmadığından emin olmak için atama kullanmaktır. Aşağıdaki kod, atamayı zorlamak için bir atma kullanır. Atamanın sağ tarafında bağımsız değişken olduğunda bir atmak için null birleşim işleci kullanılırnull.System.ArgumentNullException Kod atamanın sonucuna ihtiyaç duymadığından atılır. İfade null denetime zorlar. Atma, amacınızı netleştirir: atamanın sonucu gerekli değildir veya kullanılmaz.

public static void Method(string arg)
{
    _ = arg ?? throw new ArgumentNullException(paramName: nameof(arg), message: "arg can't be null");

    // Do work with arg.
}

Aşağıdaki örnek, zaman uyumsuz bir işlem tarafından döndürülen nesneyi yoksaymak Task için tek başına atma kullanır. Görevin atanması, işlemin tamamlanmak üzere olduğu için attığı özel durumu gizleme etkisine sahiptir. Amacınızı netleştirir: öğesini atmak Taskve bu zaman uyumsuz işlemden oluşturulan hataları yoksaymak istiyorsunuz.

private static async Task ExecuteAsyncMethods()
{
    Console.WriteLine("About to launch a task...");
    _ = Task.Run(() =>
    {
        var iterations = 0;
        for (int ctr = 0; ctr < int.MaxValue; ctr++)
            iterations++;
        Console.WriteLine("Completed looping operation...");
        throw new InvalidOperationException();
    });
    await Task.Delay(5000);
    Console.WriteLine("Exiting after 5 second delay");
}
// The example displays output like the following:
//       About to launch a task...
//       Completed looping operation...
//       Exiting after 5 second delay

Görevi ataya atamadan aşağıdaki kod bir derleyici uyarısı oluşturur:

private static async Task ExecuteAsyncMethods()
{
    Console.WriteLine("About to launch a task...");
    // CS4014: Because this call is not awaited, execution of the current method continues before the call is completed.
    // Consider applying the 'await' operator to the result of the call.
    Task.Run(() =>
    {
        var iterations = 0;
        for (int ctr = 0; ctr < int.MaxValue; ctr++)
            iterations++;
        Console.WriteLine("Completed looping operation...");
        throw new InvalidOperationException();
    });
    await Task.Delay(5000);
    Console.WriteLine("Exiting after 5 second delay");

Not

Bir hata ayıklayıcısı kullanarak önceki iki örnekten birini çalıştırırsanız, özel durum oluştuğunda hata ayıklayıcı programı durdurur. Bir hata ayıklayıcısı eklenmeden, her iki durumda da özel durum sessizce yoksayılır.

_ aynı zamanda geçerli bir tanımlayıcıdır. Desteklenen bir bağlamın dışında kullanıldığında, atma olarak değil geçerli _ bir değişken olarak değerlendirilir. Adlı _ bir tanımlayıcı zaten kapsamdaysa, tek başına atma olarak kullanılması _ aşağıdakilere neden olabilir:

  • Hedeflenen atma değerini atayarak kapsam _ içi değişkenin değerinin yanlışlıkla değiştirilmesi. Örneğin:
    private static void ShowValue(int _)
    {
       byte[] arr = [0, 0, 1, 2];
       _ = BitConverter.ToInt32(arr, 0);
       Console.WriteLine(_);
    }
     // The example displays the following output:
     //       33619968
    
  • Tür güvenliğini ihlal etmek için derleyici hatası. Örneğin:
    private static bool RoundTrips(int _)
    {
       string value = _.ToString();
       int newValue = 0;
       _ = Int32.TryParse(value, out newValue);
       return _ == newValue;
    }
    // The example displays the following compiler error:
    //      error CS0029: Cannot implicitly convert type 'bool' to 'int'
    
  • Derleyici hatası CS0136, "'_' adlı yerel veya parametre bu kapsamda bildirilemiyor çünkü bu ad, yerel veya parametre tanımlamak için kapsayan bir yerel kapsamda kullanılıyor." Örneğin:
     public void DoSomething(int _)
    {
     var _ = GetValue(); // Error: cannot declare local _ when one is already in scope
    }
    // The example displays the following compiler error:
    // error CS0136:
    //       A local or parameter named '_' cannot be declared in this scope
    //       because that name is used in an enclosing local scope
    //       to define a local or parameter
    

Ayrıca bkz.