Sdílet prostřednictvím


Ignorování – Základy programování v C#

Vyřazené jsou zástupné proměnné, které jsou záměrně nevyužívané v kódu aplikace. "Diskardy odpovídají nepřiřazeným proměnným; nepředstavují hodnotu." Zahození oznamuje záměr kompilátoru a dalším uživatelům, kteří čtou váš kód: Chtěli jste ignorovat výsledek výrazu. Můžete chtít ignorovat výsledek nějakého výrazu, jednoho nebo více členů výrazu typu n-tice, parametr out pro metodu nebo cíl výrazu pro porovnání vzorů.

Další prvky kódovaných položek objasňují záměr vašeho kódu. Zahození znamená, že náš kód proměnnou nikdy nepoužívá. Vylepšují jeho čitelnost a udržovatelnost.

Označujete, že proměnná je zahozená tím, že ji přiřadíte podtržítko (_) jako její název. Například následující volání metody vrátí n-tici, ve které jsou první a druhé hodnoty ignorovány. area je proměnná, která byla dříve deklarována a je nastavena na třetí součást vrácenou GetCityInformation:

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

Můžete zahazovat nepoužité vstupní parametry lambda výrazu. Další informace najdete v části Vstupní parametry výrazu lambda článku Výrazy lambda .

** Pokud je _ platné odložení, pokus o načtení jeho hodnoty nebo použití v operaci přiřazení vygeneruje chybu kompilátoru CS0103: "Název '_' neexistuje v aktuálním kontextu". Tato chyba je způsobena tím, že _ není přiřazena hodnota a nemusí mít ani přidělené úložné místo. Pokud se jednalo o skutečnou proměnnou, nepodařilo se vám zahodit více než jednu hodnotu, jak tomu bylo v předchozím příkladu.

Dekonstrukce n-tice a objektu

Odhazování je užitečné při práci s n-ticemi, když kód aplikace používá některé prvky n-tic, ale ignoruje ostatní. Například následující QueryCityDataForYears metoda vrátí n-tici s názvem města, jeho rozlohou, rokem, počtem obyvatel města pro daný rok, dalším rokem a počtem obyvatel města pro tento druhý rok. Příklad ukazuje změnu populace mezi těmito dvěma roky. Z dat dostupných z řazené kolekce členů jsme nespokojení s oblastí města a známe název města a dvě data v době návrhu. V důsledku toho nás zajímají pouze dvě hodnoty základního souboru uložené v řazené kolekci členů a můžeme zpracovat zbývající hodnoty jako zahozené.

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

Další informace o dekonstrukci n-tic s použitím vynechání naleznete v tématu Dekonstrukce n-tic a dalších typů.

Metoda Deconstruct třídy, struktury nebo rozhraní také umožňuje načíst a dekonstruovat konkrétní sadu dat z objektu. Pokud chcete pracovat jenom s podmnožinou dekonstruovaných hodnot, můžete použít zahození. Následující příklad dekonstruuje Person objekt do čtyř řetězců (křestní jméno a příjmení, město a stát), ale zahodí příjmení a stát.

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!
        }
    }
}

Další informace o dekonstrukci uživatelem definovaných typů pomocí zahození naleznete v tématu Dekonstrukce řazených kolekcí členů a dalších typů.

Porovnávání vzorů s switch

Vzor zahození lze použít ve vzorovém porovnávání s výrazem switch. Každý výraz, včetně null, vždy odpovídá vzoru zahození.

Následující příklad definuje metodu ProvidesFormatInfo , která používá switch výraz k určení, zda objekt poskytuje IFormatProvider implementaci a testuje, zda objekt je null. Používá také vzor zahození ke zpracování objektů jiného typu, které nejsou nulové.

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

Volání metod prostřednictvím parametru out

Při volání metody Deconstruct k dekonstruování uživatelem definovaného typu (instance třídy, struktury nebo rozhraní) můžete zahodit jednotlivé hodnoty argumentů out. Můžete ale také zahodit hodnotu argumentů out při volání jakékoli metody s parametrem out .

Následující příklad volá Metodu DateTime.TryParse(String, out DateTime), která určuje, zda je řetězcové vyjádření data platné v aktuální jazykové verzi. Vzhledem k tomu, že příklad se zabývá pouze ověřením řetězce kalendářního data a nikoli analýzou data, out argument metody je zahozen.

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

Samostatné zahození

Pomocí samostatného zahození můžete označit libovolnou proměnnou, kterou chcete ignorovat. Jedním z typických použití je použití přiřazení k zajištění, že argument není null. Následující kód používá odložení, aby vynutil přiřazení. Pravá strana přiřazení používá operátor nulového sjednocení k vyvolání System.ArgumentNullException, když je argument null. Kód nepotřebuje výsledek přiřazení, takže se zahodí. Výraz vynucuje kontrolu nulové hodnoty. Zahození upřesňuje váš záměr: výsledek přiřazení není potřeba ani použit.

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

    // Do work with arg.
}

Následující příklad používá samostatnou zahození k ignorování objektu Task vráceného asynchronní operací. Přiřazení úlohy má vliv na potlačení upozornění kompilátoru na nepozorované výjimky. Váš záměr je jasný: Chcete zahodit Task a předat jakékoli chyby vygenerované z této asynchronní operace volajícím.

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

Bez přiřazení úlohy k zahození vygeneruje následující kód upozornění kompilátoru:

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");

Poznámka:

Pokud spustíte některou z předchozích dvou ukázek pomocí ladicího programu, ladicí program program zastaví při vyvolání výjimky. Bez připojeného ladicího programu se výjimka v obou případech tiše ignoruje.

_ je také platný identifikátor. Při použití mimo podporovaný kontext se _ nebere jako zahození, ale jako platná proměnná. Pokud je identifikátor _ již v oboru, použití _ jako samostatného zahození může vést k:

  • Náhodná úprava hodnoty proměnné v rozsahu platnosti _ tím, že jí přiřadíte hodnotu, která měla být zahozena. Například:
    private static void ShowValue(int _)
    {
       byte[] arr = [0, 0, 1, 2];
       _ = BitConverter.ToInt32(arr, 0);
       Console.WriteLine(_);
    }
     // The example displays the following output:
     //       33619968
    
  • Chyba kompilátoru pro porušení bezpečnosti typů. Například:
    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'
    

Viz také