Demetleri ve diğer türleri ayrıştırma
Kayıt düzeni, bir yöntem çağrısından birden çok değer almanın hafif bir yolunu sağlar. Ancak, tanımlama grubunu aldıktan sonra ayrı öğelerini işlemeniz gerekir. Aşağıdaki örnekte gösterildiği gibi öğe öğe temelinde, her ikisi de tam olarak çalışır. QueryCityDataYöntemi üç tanımlama grubu döndürür ve öğelerinin her biri ayrı bir işlemde bir değişkene atanır.
public class Example
{
public static void Main()
{
var result = QueryCityData("New York City");
var city = result.Item1;
var pop = result.Item2;
var size = result.Item3;
// Do something with the data.
}
private static (string, int, double) QueryCityData(string name)
{
if (name == "New York City")
return (name, 8175133, 468.48);
return ("", 0, 0);
}
}
Bir nesneden birden çok alan ve özellik değeri alınması eşit bir şekilde olabilir: üye üye temelinde bir değişkene bir alan veya özellik değeri atamanız gerekir.
C# 7,0 ve üzeri sürümlerde, bir tanımlama grubundan birden fazla öğe alabilir veya tek bir Yapı işlemindeki bir nesneden birden fazla alan, özellik ve hesaplanan değer alabilirsiniz. Bir kayıt düzeni oluşturmak için, öğelerini ayrı değişkenlere atarsınız. Bir nesneyi kaldırdığınızda, seçili değerleri ayrı değişkenlere atarsınız.
Demetler
C# özellikleri, tek bir işlemde bir kayıt grubundaki tüm öğeleri paketlemenizi sağlayan tanımlama grupları için yerleşik destek sunar. Bir kayıt düzeni oluşturmak için genel sözdizimi, bir tanımlama sözdizimine benzer. bir atama ifadesinin sol tarafında parantez içine atanacak olan değişkenleri çevrelemektir. Örneğin, aşağıdaki ifade dört öğeli öğe öğelerini dört ayrı değişkene atar:
var (name, address, city, zip) = contact.GetAddressInfo();
Tanımlama grubu oluşturmanın üç yolu vardır:
Her alanın türünü parantez içinde açık bir şekilde bildirebilirsiniz. Aşağıdaki örnek, yöntemi tarafından döndürülen üç tanımlama grubunu oluşturmak için bu yaklaşımı kullanır
QueryCityData.public static void Main() { (string city, int population, double area) = QueryCityData("New York City"); // Do something with the data. }varC# ' ın her değişkenin türünü bilmesi için anahtar sözcüğünü kullanabilirsiniz.varAnahtar sözcüğünü parantezlerin dışında yerleştirebilirsiniz. Aşağıdaki örnek, yöntem tarafından döndürülen üç kayıt düzeni oluştururken tür çıkarımı kullanırQueryCityData.public static void Main() { var (city, population, area) = QueryCityData("New York City"); // Do something with the data. }varAnahtar sözcüğünü, parantez içindeki değişken bildirimlerinin herhangi biri veya tümü ile ayrı ayrı de kullanabilirsiniz.public static void Main() { (string city, var population, var area) = QueryCityData("New York City"); // Do something with the data. }Bu, kısaberdir ve önerilmez.
Son olarak, tanımlama grubunu zaten önceden tanımlanmış değişkenler halinde oluşturabilirsiniz.
public static void Main() { string city = "Raleigh"; int population = 458880; double area = 144.8; (city, population, area) = QueryCityData("New York City"); // Do something with the data. }C# 10 ' dan başlayarak, değişken bildirimini ve atamayı bir dederde karıştırabilirsiniz.
public static void Main() { string city = "Raleigh"; int population = 458880; (city, population, double area) = QueryCityData("New York City"); // Do something with the data. }
Kayıt grubundaki her alan aynı türde olsa bile, parantez dışında belirli bir tür belirtemezsiniz. Bunun yapılması derleyici hatası CS8136, "Deinşaat" var (...) ' formu, ' var ' için belirli bir türe izin vermez. ".
Kayıt düzeninin her bir öğesini bir değişkene atamanız gerekir. Herhangi bir öğeyi atlarsanız, derleyici hata CS8132 oluşturuyor, "' x ' öğelerinden oluşan bir demet ' y ' değişkenlerine parçalanmayabilir."
Atma ile demet öğeleri
Genellikle bir kayıt düzeni oluştururken yalnızca bazı öğelerin değerleriyle ilgileniyorsunuz. C# 7,0 ' den başlayarak,, değerlerini yok saymayı seçtiğiniz salt yazılır değişkenler olan, C# ' nin atma desteğinden faydalanabilirsiniz. Bir atamada bir alt çizgi karakteri ("") tarafından bir atma seçilir _ . İstediğiniz sayıda değeri atabilirsiniz; tümü, tek atma tarafından temsil edilir _ .
Aşağıdaki örnek, atma ile başlıkların kullanımını gösterir. Bu QueryCityDataForYears Yöntem, şehir adı, alanı, bir yıl, bu yıl için şehir popülasyonu, ikinci yıl ve bu ikinci yıl için şehir popülasyonu içeren altı kayıt döndürür. Örnek, bu iki yıl arasındaki popülasyondaki değişikliği gösterir. Kayıt kümesinden kullanılabilen veriler, şehir alanıyla ilgilentik ve tasarım zamanında şehir adını ve iki tarihi biliyoruz. Sonuç olarak, yalnızca kayıt düzeninde depolanan iki popülasyon değeri ile ilgileniyoruz ve kalan değerlerini atma olarak işleyebilir.
using System;
public class ExampleDiscard
{
public static void Main()
{
var (_, _, _, pop1, _, pop2) = QueryCityDataForYears("New York City", 1960, 2010);
Console.WriteLine($"Population change, 1960 to 2010: {pop2 - pop1:N0}");
}
private 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
Kullanıcı tanımlı türler
C#, record ve DictionaryEntry türleri dışında demet olmayan türler oluşturmak için yerleşik destek sunmaz. Ancak, bir sınıfın yazarı, bir struct veya Interface olarak, bir veya daha fazla yöntem uygulayarak tür örneklerinin çıkarılması için izin verebilirsiniz Deconstruct . Yöntemi void döndürür ve kaldırılacak her değer, yöntem imzasında bir Out parametresi ile belirtilir. Örneğin, Deconstruct bir sınıfın aşağıdaki yöntemi Person Birinci, orta ve soyadı döndürür:
public void Deconstruct(out string fname, out string mname, out string lname)
Daha sonra Person p Aşağıdaki kod gibi bir atamayla adlı sınıfının bir örneğini kaldırabilirsiniz:
var (fName, mName, lName) = p;
Aşağıdaki örnek, Deconstruct bir nesnesinin özelliklerinin çeşitli birleşimlerini döndürmek için yöntemini aşırı yükler Person . Tek tek aşırı yükleme dönüşü:
- Ad ve soyadı.
- Birinci, orta ve soyadı.
- Ad, soyadı, şehir adı ve durum adı.
using System;
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;
}
}
public class ExampleClassDeconstruction
{
public static void Main()
{
var p = new Person("John", "Quincy", "Adams", "Boston", "MA");
// Deconstruct the person object.
var (fName, lName, city, state) = p;
Console.WriteLine($"Hello {fName} {lName} of {city}, {state}!");
}
}
// The example displays the following output:
// Hello John Adams of Boston, MA!
DeconstructAynı sayıda parametreye sahip birden çok yöntem belirsiz. DeconstructFarklı sayıda parametreye veya "parametre sayısına" sahip yöntemleri tanımlamaya dikkat etmeniz gerekir. Deconstruct aynı sayıda parametreye sahip Yöntemler aşırı yükleme çözümlemesi sırasında ayırt edilemez.
Atılmalı Kullanıcı tanımlı tür
Tanımlama gruplarıile yaptığınız gibi, bir yöntem tarafından döndürülen seçili öğeleri yoksaymak için atarsa ' u kullanabilirsiniz Deconstruct . Her atma "" adlı bir değişken tarafından tanımlanır _ ve tek bir ayrıştırma işlemi birden çok atma içerebilir.
Aşağıdaki örnek, bir Person nesnesini dört dizeye (ilk ve son adlar, şehir ve eyalet) ayırır, ancak son adı ve durumu atar.
// Deconstruct the person object.
var (fName, _, city, _) = p;
Console.WriteLine($"Hello {fName} of {city}!");
// The example displays the following output:
// Hello John of Boston!
Kullanıcı tanımlı türler için uzantı yöntemleri
Bir sınıf, yapı veya arabirim yazmadıysanız, ilgilendiğiniz değerleri döndürmek için bir veya daha fazla Deconstruct genişletme yöntemi uygulayarak o türdeki nesneleri yine de oluşturabilirsiniz.
Aşağıdaki örnek Deconstruct , sınıfı için iki genişletme yöntemini tanımlar System.Reflection.PropertyInfo . İlki, özelliğin özelliklerini gösteren, türü, statik mi, örnek mi olduğunu, salt okunurdur ve dizine eklenip eklenmeyeceğini içeren bir değerler kümesi döndürür. İkincisi, özelliğin erişilebilirliğini gösterir. Get ve set erişimcilerinin erişilebilirliği farklı olabileceğinden, Boole değerleri özelliğin ayrı Get ve set erişimcilerine sahip olup olmadığını ve varsa aynı erişilebilirliği içerip içermediğini gösterir. Yalnızca bir erişimci veya hem Get hem de set erişimcisinin aynı erişilebilirliği varsa access değişkeni, özelliğin erişilebilirliğini bir bütün olarak gösterir. Aksi takdirde, Get ve set erişimcilerinin erişilebilirliği getAccess ve değişkenleri tarafından gösterilir setAccess .
using System;
using System.Collections.Generic;
using System.Reflection;
public static class ReflectionExtensions
{
public static void Deconstruct(this PropertyInfo p, out bool isStatic,
out bool isReadOnly, out bool isIndexed,
out Type propertyType)
{
var getter = p.GetMethod;
// Is the property read-only?
isReadOnly = ! p.CanWrite;
// Is the property instance or static?
isStatic = getter.IsStatic;
// Is the property indexed?
isIndexed = p.GetIndexParameters().Length > 0;
// Get the property type.
propertyType = p.PropertyType;
}
public static void Deconstruct(this PropertyInfo p, out bool hasGetAndSet,
out bool sameAccess, out string access,
out string getAccess, out string setAccess)
{
hasGetAndSet = sameAccess = false;
string getAccessTemp = null;
string setAccessTemp = null;
MethodInfo getter = null;
if (p.CanRead)
getter = p.GetMethod;
MethodInfo setter = null;
if (p.CanWrite)
setter = p.SetMethod;
if (setter != null && getter != null)
hasGetAndSet = true;
if (getter != null)
{
if (getter.IsPublic)
getAccessTemp = "public";
else if (getter.IsPrivate)
getAccessTemp = "private";
else if (getter.IsAssembly)
getAccessTemp = "internal";
else if (getter.IsFamily)
getAccessTemp = "protected";
else if (getter.IsFamilyOrAssembly)
getAccessTemp = "protected internal";
}
if (setter != null)
{
if (setter.IsPublic)
setAccessTemp = "public";
else if (setter.IsPrivate)
setAccessTemp = "private";
else if (setter.IsAssembly)
setAccessTemp = "internal";
else if (setter.IsFamily)
setAccessTemp = "protected";
else if (setter.IsFamilyOrAssembly)
setAccessTemp = "protected internal";
}
// Are the accessibility of the getter and setter the same?
if (setAccessTemp == getAccessTemp)
{
sameAccess = true;
access = getAccessTemp;
getAccess = setAccess = String.Empty;
}
else
{
access = null;
getAccess = getAccessTemp;
setAccess = setAccessTemp;
}
}
}
public class ExampleExtension
{
public static void Main()
{
Type dateType = typeof(DateTime);
PropertyInfo prop = dateType.GetProperty("Now");
var (isStatic, isRO, isIndexed, propType) = prop;
Console.WriteLine($"\nThe {dateType.FullName}.{prop.Name} property:");
Console.WriteLine($" PropertyType: {propType.Name}");
Console.WriteLine($" Static: {isStatic}");
Console.WriteLine($" Read-only: {isRO}");
Console.WriteLine($" Indexed: {isIndexed}");
Type listType = typeof(List<>);
prop = listType.GetProperty("Item",
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
var (hasGetAndSet, sameAccess, accessibility, getAccessibility, setAccessibility) = prop;
Console.Write($"\nAccessibility of the {listType.FullName}.{prop.Name} property: ");
if (!hasGetAndSet | sameAccess)
{
Console.WriteLine(accessibility);
}
else
{
Console.WriteLine($"\n The get accessor: {getAccessibility}");
Console.WriteLine($" The set accessor: {setAccessibility}");
}
}
}
// The example displays the following output:
// The System.DateTime.Now property:
// PropertyType: DateTime
// Static: True
// Read-only: True
// Indexed: False
//
// Accessibility of the System.Collections.Generic.List`1.Item property: public
Sistem türleri için genişletme yöntemi
Bazı sistem türleri Deconstruct bir kolaylık olarak yöntemi sağlar. Örneğin, System.Collections.Generic.KeyValuePair<TKey,TValue> tür bu işlevselliği sağlar. Her bir öğe üzerinde yineleirken System.Collections.Generic.Dictionary<TKey,TValue> , KeyValuePair<TKey, TValue> ve oluşturulabilirler. Aşağıdaki örneği inceleyin:
Dictionary<string, int> snapshotCommitMap = new(StringComparer.OrdinalIgnoreCase)
{
["https://github.com/dotnet/docs"] = 16_465,
["https://github.com/dotnet/runtime"] = 114_223,
["https://github.com/dotnet/installer"] = 22_436,
["https://github.com/dotnet/roslyn"] = 79_484,
["https://github.com/dotnet/aspnetcore"] = 48_386
};
foreach (var (repo, commitCount) in snapshotCommitMap)
{
Console.WriteLine(
$"The {repo} repository had {commitCount:N0} commits as of November 10th, 2021.");
}
DeconstructBir yöntemi, bir sistem türlerine sahip olmayan bir yöntem ekleyebilirsiniz. Aşağıdaki genişletme yöntemini göz önünde bulundurun:
public static class NullableExtensions
{
public static void Deconstruct<T>(
this T? nullable,
out bool hasValue,
out T value) where T : struct
{
hasValue = nullable.HasValue;
value = nullable.GetValueOrDefault();
}
}
Bu genişletme yöntemi, tüm Nullable<T> türlerin bir demet içinde oluşturulmasına izin verir (bool hasValue, T value) . Aşağıdaki örnek, bu genişletme yöntemini kullanan kodu gösterir:
DateTime? questionableDateTime = default;
var (hasValue, value) = questionableDateTime;
Console.WriteLine(
$"{{ HasValue = {hasValue}, Value = {value} }}");
questionableDateTime = DateTime.Now;
(hasValue, value) = questionableDateTime;
Console.WriteLine(
$"{{ HasValue = {hasValue}, Value = {value} }}");
// Example outputs:
// { HasValue = False, Value = 1/1/0001 12:00:00 AM }
// { HasValue = True, Value = 11/10/2021 6:11:45 PM }
record türü
İki veya daha fazla Konumsal parametre kullanarak bir kayıt türü bildirdiğinizde, derleyici, Deconstruct out bildirimdeki her Konumsal parametre için parametresiyle bir yöntem oluşturur record . Daha fazla bilgi için, bkz. özellik tanımı Için konumsal sözdizimi ve türetilmiş kayıtlarda Deconstructor davranışı.