Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Uyarı
Bu makale bir özellik belirtimidir. Belirtim, özelliğin tasarım belgesi olarak görev alır. Önerilen belirtim değişikliklerini ve özelliğin tasarımı ve geliştirilmesi sırasında gereken bilgileri içerir. Bu makaleler, önerilen belirtim değişiklikleri son haline getirilene ve geçerli ECMA belirtimine dahil edilene kadar yayımlanır.
Özellik belirtimi ile tamamlanan uygulama arasında bazı tutarsızlıklar olabilir. Bu farklılıklar ilgili dil tasarım toplantısı (LDM) notlarında yakalanır.
Özellik belirtimlerini C# dil standardına benimseme işlemi hakkında daha fazla bilgi edinmek için
Şampiyonluk sorunu: https://github.com/dotnet/csharplang/issues/9662
Özet
Birleşimler , birleşim türleri için C# desteği sağlamak üzere birleştirilen bir dizi birbirine bağlantılı özelliktir:
-
Birleşim türleri: Özniteliği olan
[Union]yapılar ve sınıflar birleşim türleri olarak kabul edilir ve birleşim davranışlarını destekler. - Durum türleri: Birleşim türleri, oluşturuculara ve fabrika yöntemlerine parametreler tarafından verilen bir servis talebi türleri kümesine sahiptir.
-
Birleşim davranışları: Birleşim türleri aşağıdaki birleşim davranışlarını destekler:
- Birleşim dönüştürmeleri: Her büyük/küçük harf türünden bir birleşim türüne örtük birleşim dönüştürmeleri vardır.
- Birleşim eşleştirme: Birleşim değerleriyle desen eşleştirme örtük olarak içeriklerini "çıkararak" deseni temel alınan değere uygular.
- Birleşim kapsamlılığı: Birleşim değerleri üzerindeki anahtar ifadeleri, tüm servis talebi türleri eşleştirildiğinde, geri dönüş olayına gerek kalmadan çok kapsamlıdır.
- Union nullability: Nullability çözümlemesi, bir birleşimin içeriğinin null durumunun izlenmesini geliştirdi.
- Birleşim desenleri: Tüm birleşim türleri temel bir birleşim deseni izler, ancak belirli senaryolar için ek isteğe bağlı desenler vardır.
- Birleşim bildirimleri: Kısaltma söz dizimi birleşim türlerinin doğrudan bildirılmasına olanak tanır. Uygulama "opinionated" - temel birleşim desenini izleyen ve içeriği tek bir başvuru alanı olarak depolayan bir yapı bildirimidir.
- Birleşim arabirimleri: Dil tarafından bilinen ve birleşim bildirimlerinin uygulanmasında kullanılan birkaç arabirim.
Motivasyon
Birleşimler, kapalı bir tür kümesindeki değerlerin desen eşleştirmenin kapsamlı olmasına güvenebilecek şekilde ifade edilmesini sağlayan, uzun süredir istenen bir C# özelliğidir.
Birleşim türleri ve birleşim bildirimleri arasındaki ayrım, C# öğesinin belirsiz semantik içeren kısa bir birleşim bildirimi söz dizimine sahip olmasını sağlarken, diğer uygulama seçeneklerine sahip mevcut türlerin veya türlerin birleşim davranışlarını kabul etmesine de olanak tanır.
C# dilinde önerilen birleşimler türlerin birleşimleridir ve "ayrımcı" veya "etiketli" değildir. "Ayrımcı birleşimler", durum türleri olarak yeni tür bildirimleri kullanılarak "tür birleşimleri" olarak ifade edilebilir. Alternatif olarak, kapsamlılığa odaklanan bir diğer ilgili, yaklaşan C# özelliği olan kapalı bir hiyerarşi olarak da uygulanabilirler.
Ayrıntılı tasarım
Birleşim türleri
Özniteliği olan herhangi bir System.Runtime.CompilerServices.UnionAttribute sınıf veya yapı türü birleşim türü olarak kabul edilir:
namespace System.Runtime.CompilerServices
{
[AttributeUsage(Class | Struct, AllowMultiple = false)]
public class UnionAttribute : Attribute;
}
Birleşim türü, birleşim türünün kendisinde bildirilmesi veya bir "birleşim üyesi sağlayıcısına" temsilci olarak atanması gereken belirli bir genel birleşim üyeleri desenini izlemelidir.
Bazı sendika üyeleri zorunludur ve diğerleri isteğe bağlıdır.
Birleşim türü, belirli birleşim üyelerinin imzalarına göre oluşturulmuş bir servis talebi türleri kümesine sahiptir.
Birleşim değerinin içeriğine bir Value özellik aracılığıyla erişilebilir. Dil, yalnızca büyük/küçük harf türlerinden birinin değerini veya null değerini içerdiğini varsayar Value (bkz . İyi biçimlendirilmişlik).
Birleşim üyesi sağlayıcılar
Varsayılan olarak, birleşim üyeleri birleşim türünün kendisinde bulunur. Bununla birlikte, birleşim türü doğrudan adlı IUnionMembers bir arabirimin bildirimini içeriyorsa, arabirim birleşim üyesi sağlayıcısı olarak davranır. Bu durumda, birleşim üyeleri birleşim türünün kendisinde değil , yalnızca birleşim üyesi sağlayıcısında bulunur.
Birleşim üyesi sağlayıcı arabiriminin genel olması ve birleşim türünün kendisini arabirim olarak uygulaması gerekir.
Birleşim üyelerinin bulunduğu tür için birleşim tanımlama türü terimini kullanırız: Varsa birleşim üyesi sağlayıcısı ve aksi takdirde birleşim türü.
Sendika üyeleri
Birleşim üyeleri, birleşim tanımlama türünde ada ve imzaya göre aranıyor. Birleşim tanımlama türünde doğrudan bildirilmesi gerekmez, ancak devralınabilir.
Herhangi bir birleşim üyesinin genel olmaması bir hatadır.
Oluşturma üyeleri ve Value özelliği zorunlu olup, topluca temel birleşim deseni olarak adlandırılır.
HasValue ve TryGetValue üyeleri topluca kutulama olmayan birleşim erişim deseni olarak adlandırılır.
Farklı birleşim üyeleri aşağıda açıklanmıştır.
Birleşim oluşturma üyeleri
Birleşim oluşturma üyeleri, bir servis talebi türü değerinden yeni birleşim değerleri oluşturmak için kullanılır.
Birleşim tanımlayıcı türü birleşim türünün kendisiyse, tek parametreli her oluşturucu bir birleşim oluşturucudur. Birleşimin büyük/küçük harf türleri, bu oluşturucuların parametre türlerinden aşağıdaki şekilde oluşturulan tür kümesi olarak tanımlanır:
- Parametre türü null atanabilir bir türse (değer veya başvuru), büyük/küçük harf türü temel alınan türdür
- Aksi takdirde, büyük/küçük harf türü parametre türüdür.
// Union constructor making `Dog` a case type
public Pet(Dog value) { ... }
// Union constructor making `int` a case type
public Union(int? value) { ... }
// Union constructor making `string` a case type
public Union(string? value) { ... }
Birleşim tanımlama türü bir birleşim üyesi sağlayıcısıysa, tek bir parametreye ve birleşim türüne kimlik dönüştürülebilir dönüş türüne sahip her statik Createyöntem bir birleşim fabrikası yöntemidir.
Birleşimin durum türleri, aşağıdaki şekilde bu fabrika yöntemlerinin parametre türlerinden oluşturulan tür kümesi olarak tanımlanır:
- Parametre türü null atanabilir bir türse (değer veya başvuru), büyük/küçük harf türü temel alınan türdür
- Aksi takdirde, büyük/küçük harf türü parametre türüdür.
// Union factory method making `Cat` a case type
public static Pet Create(Cat value) { ... }
// Union factory method making `int` a case type
public static Union Create(int? value) { ... }
// Union factory method making `string` a case type
public static Union Create(string? value) { ... }
Birleşim oluşturucuları ve birleşim fabrikası yöntemleri topluca birleşim oluşturma üyeleri olarak adlandırılır.
Birleşim oluşturma üyesinin tek parametresi bir değere veya in parametreye göre olmalıdır.
Birleşim türü en az bir birleşim oluşturma üyesine ve bu nedenle en az bir servis talebi türüne sahip olmalıdır.
Value özelliği
özelliği, Value büyük/küçük harf türünden bağımsız olarak birleşimde yer alan değere erişim sağlar.
Birleşim tanımlayan her tür, veya objecttüründe object? bir Value özellik bildirmelidir. Özelliğin bir erişimcisi olmalıdır ve isteğe bağlı olarak herhangi bir get erişilebilirlikte olabilen ve derleyici tarafından kullanılmayan bir init veya set erişimcisine sahip olabilir.
// Union 'Value' property
public object? Value { get; }
Kutulanmayan erişim üyeleri
Birleşim türü, her servis talebi türüne kesin olarak yazılan koşullu erişime ve null değerini denetlemenin bir yoluna olanak tanıyan kutulama olmayan birleşim erişim desenini de uygulamayı seçebilir.
Bu, büyük/küçük harf türleri değer türleri olduğunda ve birleşim içinde bu şekilde depolandığında derleyicinin desen eşleştirmeyi daha verimli bir şekilde uygulamasına olanak tanır.
Kutulanmayan erişim üyeleri şunlardır:
- Ortak
HasValuegeterişimci ile türündeboolbir özellik. İsteğe bağlı olarak herhangi bir erişilebilirlikte olabilen ve derleyici tarafından kullanılmayan birinitveyaseterişimcisine sahip olabilir. -
TryGetValueHer durum türü için bir yöntem. yöntemi döndürürboolve kimlik-büyük/küçük harf türüne dönüştürülebilir bir türün tek bir out-parameter alır.
// Non-boxing access members
public bool HasValue { get { ... } }
public bool TryGetValue(out Dog value) { ... }
HasValue yalnızca birleşim Value null değilse true döndürmesi beklenir.
TryGetValue yalnızca birleşim Value verilen büyük/küçük harf türündeyse true döndürmesi beklenir ve öyleyse yöntemin out parametresinde bu değeri teslim edin.
İyi biçimlilik
Dil ve derleyici birleşim türleri hakkında bir dizi davranışsal varsayımda bulunur. Bir tür birleşim türü olarak niteleniyor ancak bu varsayımları karşılamıyorsa, birleşim davranışları beklendiği gibi çalışmayabilir.
-
Ses:
Valueözelliği her zaman null veya bir servis talebi türünde bir değer olarak değerlendirilir. Birleşim türünün varsayılan değeri için bile bu geçerlidir. -
Kararlılık: Bir büyük/küçük harf türünden birleşim değeri oluşturulursa,
Valueözellik bu büyük/küçük harf türü veya null ile eşleşecektir. Bir değerdennullbirleşim değeri oluşturulursa özelliğiValueolurnull. - Oluşturma eşdeğerliği: Bir değer örtük olarak iki farklı büyük/küçük harf türüne dönüştürülebilirse, bu durum türlerinden herhangi birinin oluşturma üyesi, bu değerle çağrıldığında aynı gözlemlenebilir davranışa sahiptir.
-
Erişim deseni tutarlılığı: Varsa ve
TryGetValuekutulanmayanHasValueerişim üyelerinin davranışı, doğrudan özellik üzerinde denetim yapma işlemiyleValueeşdeğerdir.
Birleşim türleri örnekleri
Pet birleşim türünün kendisinde temel birleşim desenini uygular:
[Union] public record struct Pet
{
// Creation members = case types are 'Dog' and 'Cat'
public Pet(Dog value) => Value = value;
public Pet(Cat value) => Value = value;
// 'Value' property
public object? Value { get; }
}
IntOrBool birleşim türünün kendisinde kutulama olmayan erişim desenini uygular:
public record struct IntOrBool
{
private bool _isBool;
private int _value;
public IntOrBool(int value) => (_isBool, _value) = (false, value);
public IntOrBool(bool value) => (_isBool, _value) = (true, value ? 1 : 0);
public object Value => _isBool ? _value is 1 : _value;
public bool HasValue => true;
public bool TryGetValue(out int value)
{
value = _value;
return !_isBool;
}
public bool TryGetValue(out bool value)
{
value = _isBool && _value is 1;
return _isBool;
}
}
Not: Bu, kutulanmayan erişim deseninin nasıl uygulanabileceğini gösteren bir örnektir. Kullanıcı kodu içeriği istediği gibi depolayabilir. Özellikle uygulamanın boks yapmasını engellemez!
non-boxing adında, derleyicinin desen eşleştirme uygulamasının -typed Value özelliğinin aksine her büyük/küçük harf türüne kesin olarak belirlenmiş bir şekilde erişmesine izin verme object?anlamına gelir.
Result<T> bir birleşim üyesi sağlayıcısı aracılığıyla temel deseni uygular:
public record class Result<T> : Result<T>.IUnionMembers
{
object? _value;
public interface IUnionMembers
{
public static Result<T> Create(T value) => new() { _value = value };
public static Result<T> Create(Exception value) => new() { _value = value };
public object? Value { get; }
}
object? IUnionMembers.Value => _value;
}
Birleşim davranışları
Birleşim davranışları genellikle temel birleşim deseni yoluyla uygulanır. Birleşim, kutulama olmayan erişim deseni sunuyorsa birleşim deseni eşleştirmesi tercihen bunu kullanır.
Birleşim dönüştürmeleri
Birleşim dönüştürme örtük olarak her bir durum türünden bir birleşim türüne dönüştürür. Özellikle, bir tür veya ifadeden E bir türe U standart örtük dönüştürme E varsa ve C öğesinin birleşim oluşturma üyesinin parametre türüyse birleşim türüne C bir birleşim dönüştürmesi Uvardır.
Birleşim türü U bir yapıysa, bir tür veya ifadeden E türe U? standart örtük dönüştürme varsa ve C öğesinin birleşim oluşturma üyesinin parametre türüyse, bir birleşim dönüştürmesi UEC vardır.
Birleşim dönüştürme, standart bir örtük dönüştürme değildir. Bu nedenle kullanıcı tanımlı örtük dönüştürmeye veya başka bir birleşim dönüştürmesine katılmayabilir.
Örtük birleşim dönüştürmeleri dışında açık birleşim dönüştürmeleri yoktur. Bu nedenle, bir birleşimin E servis talebi türüne Caçık bir dönüştürme olsa bile, bu, 'den E bu birleşim türüne açık bir dönüştürme olduğu anlamına gelmez.
Birleşim dönüştürmesi, birleşim oluşturma üyesi çağrılarak yürütülür:
Pet pet = dog;
// becomes
Pet pet = new Pet(dog);
// and
Result<string> result = "Hello"
//becomes
Result<string> result = Result<string>.IUnionMembers.Create("Hello");
Aşırı yükleme çözümlemesi tek bir en iyi aday üye bulamazsa veya bu üye birleşim türünün birleşim üyelerinden biri değilse bir hatadır.
Birleşim dönüştürme, örtük kullanıcı tanımlı dönüştürmenin yalnızca başka bir "biçimidir". Geçerli kullanıcı tanımlı dönüştürme işleci "gölgeler" birleşim dönüştürmesi.
Bu kararın arkasındaki gerekçe:
Kullanıcı tanımlı bir işleç yazılmışsa önceliğe sahip olması gerekir. Başka bir deyişle, kullanıcı gerçekten kendi operatörünü yazdıysa, bunu çağırmamızı ister. Birleşim türlerine dönüştürülen dönüştürme işleçlerine sahip mevcut türler, günümüzde işleçleri kullanan mevcut kodlarla aynı şekilde çalışmaya devam ediyor.
Aşağıdaki örnekte, örtük bir kullanıcı tanımlı dönüştürme, birleşim dönüştürmesine göre önceliklidir.
struct S1 : System.Runtime.CompilerServices.IUnion
{
public S1(int x) => ...
public S1(string x) => ...
object System.Runtime.CompilerServices.IUnion.Value => ...
public static implicit operator S1(int x) => ...
}
class Program
{
static S1 Test1() => 10; // implicit operator S1(int x) is used
static S1 Test2() => (S1)20; // implicit operator S1(int x) is used
}
Aşağıdaki örnekte, kodda açık atama kullanıldığında, açık kullanıcı tanımlı dönüştürme birleşim dönüştürmesine göre önceliklidir. Ancak, kodda açık atama olmadığında, açık kullanıcı tanımlı dönüştürme geçerli olmadığından birleşim dönüştürmesi kullanılır.
struct S2 : System.Runtime.CompilerServices.IUnion
{
public S2(int x) => ...
public S2(string x) => ...
object System.Runtime.CompilerServices.IUnion.Value => ...
public static explicit operator S2(int x) => ...
}
class Program
{
static S2 Test3() => 10; // Union conversion S2.S2(int) is used
static S2 Test4() => (S2)20; // explicit operator S2(int x)
}
Birleşim eşleştirme
Bir desenin gelen değeri birleşim türünde veya birleşim türünün null atanabilir olduğunda, null atanabilir değer ve temel alınan birleşim değerinin içeriği desene bağlı olarak "eşlenmemiş" olabilir.
Koşulsuz _ ve var desenler için desen, gelen değerin kendisine uygulanır. Örneğin:
if (GetPet() is var pet) { ... } // 'pet' is the union value returned from `GetPet`
Ancak diğer tüm desenler, temel alınan birleşimin Value özelliğine örtük olarak uygulanır:
if (GetPet() is Dog dog) { ... } // 'Dog dog' is applied to 'GetPet().Value'
if (GetPet() is null) { ... } // 'null' is applied to 'GetPet().Value'
if (GetPet() is { } value) { ... } // '{ } value' is applied to 'GetPet().Value'
Mantıksal desenler için bu kural, bir and desenin sol dalının sağ dalın gelen türünü etkileyebileceği göz önünde bulundurularak dallara ayrı ayrı uygulanır:
GetPet() switch
{
var pet and not null => ... // 'var pet' applies to the incoming 'Pet' and 'not null' to its 'Value'
not null and var value => ... // 'not null' applies to the 'Value' as does 'var value' because of the
// left branch changing the incoming type to `object?`.
}
Not: Bu kural, birleşimin GetPet() is Pet pet kendisine değil Pet içeriğine uygulandığı gibi Pet büyük olasılıkla başarılı olmayacak anlamına gelir.
Not: Koşulsuz var desenin farklı bir şekilde işlenmesinin nedeni ( _ve temelde var _kısaltma olan ), kullanımlarının diğer desenlerden niteliksel olarak farklı olduğu varsayımıdır.
var desenler, genellikle gibi iç içe desenlerde eşleştirilen değeri adlandırmak için PetOwner{ Pet: var pet }kullanılır. Burada yararlı semantikpet, özelliğin işe yaramaz object? bir türe başvurulması yerine Value birleşim türünü Petkorumak için kullanılır.
Gelen değer bir sınıf türüyse, birleşim değerinin null kendisi null veya içerdiği değerden nullbağımsız olarak desen başarılı olur:
if (result is null) { ... } // if (result == null || result.Value == null)
Diğer birleşim eşleştirme desenleri yalnızca birleşim değerinin kendisi olmadığında nullbaşarılı olur.
if (result is 1) { ... } // if (result != null && result.Value is 1)
Benzer şekilde, gelen değer null atanabilir bir değer türüyse (yapı birleşim türünü sarmalama), null gelen değerin kendisi null veya içerdiği değerin nullolup olmadığına bakılmaksızın desen başarılı olur:
if (result is null) { ... } // if (result.HasValue == false || result.GetValueOrDefault().Value == null)
Diğer birleşim eşleştirme desenleri yalnızca gelen değerin kendisi olmadığında nullbaşarılı olur.
if (result is 1) { ... } // if (result.HasValue && result.GetValueOrDefault().Value is 1)
Derleyici, kutulama dışı erişim deseni tarafından belirtilen üyeler yoluyla desen davranışını uygulamayı tercih edecektir. İyi biçimlendirilmişlik kurallarının sınırları içinde herhangi bir iyileştirme yapmak ücretsiz olsa da, uygulanması garanti edilen en düşük küme şunlardır:
- Belirli bir türün
Tdenetlendiğini ima eden bir desen için, birTryGetValue(S value)yöntem varsa ve bir kimlik varsa veya 'denTSöğesine örtük başvuru/kutulama dönüştürmesi varsa, bu yöntem değeri almak için kullanılır. Desen daha sonra bu değere uygulanır. Böyle birden fazla yöntem varsa, dönüştürmeninTSkutulama dönüştürmesi olmadığı durumlar varsa tercih edilir. Yine de birden fazla yöntem varsa, uygulama tanımlı bir şekilde bir yöntem seçilir. - Aksi takdirde, bir özelliğin kullanılabilir olup olmadığını denetlemeyi ima eden bir
HasValuedesen içinnullbirleşim değerinin null olup olmadığını denetlemek için bu özellik kullanılır. - Aksi takdirde, desen gelen birleşimde özelliğine
IUnion.Valueerişmenin sonucuna uygulanır.
Birleşim türüne uygulanan is-type işleci , birleşim türüne uygulanan tür deseni ile aynı anlama sahiptir.
Birleşim tükenmesi
Birleşim türünün büyük/küçük harf türlerine göre "tükendiği" varsayılır. Bu, bir switch birleşimin servis talebi türlerinin tümünü işlediğinde ifadenin kapsamlı olduğu anlamına gelir:
var name = pet switch
{
Dog dog => ...,
Cat cat => ...,
// No warning about non-exhaustive switch
};
Null Olabilirlik
Bir birleşimin Value özelliğinin null durumu, diğer tüm özellikler gibi izlenir ve bu değişiklikler yapılır:
- Birleşim oluşturma üyesi çağrıldığında (açıkça veya birleşim dönüştürmesi aracılığıyla), yeni birleşim
Valuegelen değerin null durumunu alır. - Kutulanmayan erişim deseni
HasValueveyaTryGetValue(...)birleşim türünün içeriğini sorgulamak için kullanıldığında (açıkça veya desen eşleştirme yoluyla), 'ın null atanabilirlik durumunu doğrudan denetlenmiş gibiValueetkilerValue: Null durumuValuedaldatrue"null değil" olur.
Birleşim anahtarı aksi halde kapsamlı olsa bile, gelen birleşimin Value özelliğinin null durumu "belki null" ise, işlenmeyen null üzerinde bir uyarı verilir.
Pet pet = GetNullableDog(); // 'pet.Value' is "maybe null"
var value = pet switch
{
Dog dog => ...,
Cat cat => ...,
// Warning: 'null' not handled
}
Birleşim arabirimleri
Aşağıdaki arabirimler, birleşim özelliklerinin uygulanmasında dil tarafından kullanılır.
Birleşim erişim arabirimi
Arabirim, IUnion derleme zamanında bir türü birleşim türü olarak işaretler ve çalışma zamanında birleşim içeriğine erişmek için bir yol sağlar.
public interface IUnion
{
// The value of the union or null
object? Value { get; }
}
Derleyici tarafından oluşturulan birleşimler bu arabirimi uygular.
Örnek kullanım:
if (value is IUnion { Value: null }) { ... }
Birleşim bildirimleri
Birleşim bildirimleri, C# dilinde birleşim türlerini bildirmenin kısa ve kesin bir yoludur. Öğesini depolamak Valueiçin tek bir nesne başvurusu kullanan bir yapı bildirirler, bu da şu anlama gelir:
- Kutulama: Servis talebi türleri arasındaki tüm değer türleri girişte kutulanır.
- Sıkıştırma: Birleşim değerleri yalnızca tek bir alan içerir.
Amaç, birleşim bildirimlerinin kullanım örneklerinin büyük çoğunluğunu oldukça güzel bir şekilde kapsamasını sağlamaktır. Birleşim bildirimlerini kullanmak yerine belirli birleşim türlerini el ile kodlamanın başlıca iki nedeni şunlardır:
- Birleşim davranışları elde etmek için var olan türleri birleşim desenlerine uyarlama.
- Verimlilik veya birlikte çalışma nedenleri gibi farklı bir depolama stratejisi uygulama.
Sözdizimi
Birleşim bildiriminin adı ve birleşim oluşturucu türlerinin listesi vardır.
union_declaration
: attributes? struct_modifier* 'partial'? 'union' identifier type_parameter_list?
'(' type (',' type)* ')' struct_interfaces? type_parameter_constraints_clause*
(`{` struct_member_declaration* `}` | ';')
;
Yapı üyelerine (§16.3) yönelik kısıtlamalara ek olarak, aşağıdakiler birleşim üyeleri için de geçerlidir:
- Örnek alanlarına, otomatik özelliklere veya alan benzeri olaylara izin verilmez.
- Tek bir parametreyle açıkça bildirilen ortak oluşturuculara izin verilmez.
- Açıkça bildirilen oluşturucular, oluşturulan oluşturuculardan birine (doğrudan veya dolaylı olarak) temsilci atamak için bir
this(...)başlatıcı kullanmalıdır.
Birleşim oluşturucu türleri, arabirimlerobject, tür parametreleri, null atanabilir türler ve diğer birleşimler gibi öğesine dönüştürülen herhangi bir tür olabilir. Sonuçta ortaya çıkan durumların çakışması ve birleşimlerin iç içe veya null olması uygundur.
Examples:
// Union of existing types
public union Pet(Cat, Dog, Bird);
// Union with function member
public union OneOrMore<T>(T, IEnumerable<T>)
{
public IEnumerable<T> AsEnumerable() => Value switch
{
IEnumerable<T> list => list,
T value => [value],
}
}
// "Discriminated" union with freshly declared case types
public record class None();
public record class Some<T>(T value);
public union Option<T>(None, Some<T>);
#### Lowering
A union declaration is lowered to a struct declaration with
* the same attributes, modifiers, name, type parameters and constraints,
* implicit implementations of `IUnion`,
* a `public object? Value { get; }` auto-property,
* a public constructor for each *union constructor* type,
* any members in the union declaration's body.
It is an error for user-declared members to conflict with generated members.
Example:
``` c#
public union Pet(Cat, Dog){ ... }
Şu şekilde azaltılır:
[Union] public struct Pet : IUnion
{
public Pet(Cat value) => Value = value;
public Pet(Dog value) => Value = value;
public object? Value { get; }
... // original body
}
Açık sorular
[Çözüldü] Birleşim bildirimi bir kayıt mı?
Birleşim bildirimi bir kayıt yapısına indirilir
Bu varsayılan davranışın gereksiz olduğunu düşünüyorum ve yapılandırılabilir olmadığı için kullanım senaryolarını önemli ölçüde sınırlayacak. Kayıtlar kullanılmayan veya belirli gereksinimlerle eşleşmeyen çok sayıda kod oluşturur. Örneğin, bu kod blobu nedeniyle derleyicinin kod tabanında kayıtlar neredeyse yasaktır. Varsayılanı değiştirmenin daha iyi olacağını düşünüyorum:
- Varsayılan olarak, birleşim bildirimi yalnızca birleşime özgü üyelerle normal bir yapı bildirir.
- Kullanıcı bir kayıt birleşimini bildirebilir:
record union U(E1, ...) ...
Çözünürlük: Birleşim bildirimi, kayıt yapısı değil düz bir yapıdır.
record union ... desteklenmez
[Çözüldü] Birleşim bildirimi söz dizimi
Önerilen söz dizimi eksik veya gereksiz yere sınırlanmış gibi görünüyor. Örneğin, base yan tümcesine izin verilmiyor gibi görünüyor. Ancak, örneğin bir arabirim uygulama gereksinimini kolayca hayal edebiliyorum.
Söz diziminin element-types-list dışında, anahtar sözcüğün struct anahtar sözcükle değiştirildiği normalrecord struct/struct bildirimle union eşleşmesi gerektiğini düşünüyorum.
Çözünürlük: Kısıtlama kaldırılır.
[Çözüldü] Birleşim bildirimi üyeleri
Örnek alanlarına, otomatik özelliklere veya alan benzeri olaylara izin verilmez.
Bu rastgele ve kesinlikle gereksiz geliyor.
Çözünürlük: Kısıtlama korunur.
[Çözüldü] Union case types olarak null atanabilir değer türleri
Birleşimin durum türleri, bu oluşturuculardan parametre türleri kümesi olarak tanımlanır. Birleşimin durum türleri, bu fabrika yöntemlerinden parametre türleri kümesi olarak tanımlanır.
Aynı zamanda:
TryGetValueHer durum türü için bir yöntem. yöntemi aşağıdaki şekilde verilen büyük/küçük harf türüne karşılık gelen bir türün tek bir out-parametresini döndürürboolve alır:
- Büyük/küçük harf türü null atanabilir bir değer türüyse, parametrenin türü temel alınan türe identity-convertible olmalıdır
- Aksi takdirde, türün durum türüne identity-convertible olması gerekir.
Büyük/küçük harf türleri arasında null atanabilir değer türüne sahip olmak, özellikle de bir tür deseninin hedef tür olarak null atanabilir değer türünü kullanamamasının bir avantajı var mı? Oluşturucunun/fabrikanın parametre türü null atanabilir bir değer türüyse, karşılık gelen büyük/küçük harf türünün temel alınan tür olduğunu söyleyebiliriz. Bu durumda yöntem için bu ek yan tümceye TryGetValue ihtiyacımız olmaz, tüm dış parametreler büyük/küçük harf türleridir.
Çözünürlük: Öneri onaylandı
[Çözüldü] Varsayılan null atanabilir özellik durumu Value
Durum türlerinden hiçbirinin null atanamaz olduğu birleşim türleri için
Valuevarsayılan durum "belki null" yerine "null değil"dir.
Özelliğin bazı genel arabirimlerde tanımlanmadığı Value ancak özellikle bildirilen türe ait bir API olduğu yeni tasarımda, yukarıda belirtilen kural fazla mühendislik gibi görünür. Ayrıca kural, aksi takdirde null atanabilir türlerin kullanılmayacağı durumlarda tüketicileri null atanabilir türleri kullanmaya zorlar.
Örneğin, aşağıdaki birleşim bildirimini göz önünde bulundurun:
union U1(int, bool, DateTime);
Tırnak içine alınan kurala göre için varsayılan durum Value "null değil" şeklindedir. Ancak bu, türünün davranışıyla eşleşmez: default(U1).Valuenull. Davranışı yeniden hizalamak için tüketici en az bir durum türünü null atanabilir hale getirmek zorunda kalır. Şöyle bir şey:
union U1(int?, bool, DateTime);
Ancak bu büyük olasılıkla istenmeyen bir durumdur. Tüketici, değerle int? açık oluşturma işlemine izin vermek istemeyebilir.
Teklif: Teklif edilen kuralı kaldırın; null atanabilir analiz, varsayılan null atanabilirliğini çıkarmak için özelliğinden Value ek açıklamalar kullanmalıdır.
Çözünürlük: Teklif onaylandı
[Çözüldü] Birleşim değeri türünün Null atanabilir değeri için birleşim eşleştirmesi
Bir desenin gelen değeri birleşim türünde olduğunda, desene bağlı olarak birleşim değerinin içeriği "unwrapped" olabilir.
Bir desenin Nullable<union type>gelen değeri bir olduğunda bu kuralı senaryolara genişletmeli miyiz?
Aşağıdaki senaryoyu göz önünde bulundurun:
static bool Test1(StructUnion? u)
{
return u is 1;
}
static bool Test2(ClassUnion? u)
{
return u is 1;
}
Test1 ve Test2'deki anlamı u is 1 çok farklıdır. Test1'de birleşim eşleştirmesi değildir, Test2'de bu bir birleşimdir.
Belki de "birleşim eşleştirmesi", desen eşleştirmenin genellikle diğer durumlarda yaptığı gibi "kazmalıdır" Nullable<T> .
Bununla gidersek, birleşim eşleştirme null deseni Nullable<union type> sınıflar için olduğu gibi çalışmalıdır.
Yani desen doğru olduğunda (!nullableValue.HasValue || nullableValue.Value.Value is null).
Çözünürlük: Teklif onaylandı.
"Hatalı" API'ler hakkında ne yapmalı?
Derleyici, eşleşme gibi görünen ancak başka bir şekilde "hatalı" olan birleşim eşleştirme API'leri hakkında ne yapmalı? Örneğin, derleyici eşleşen imzaya sahip TryGetValue/HasValue değerini bulur, ancak gerekli bir özel değiştirici veya bilinmeyen bir özellik gerektirdiği için "hatalı" olur. Derleyici API'yi sessizce yoksamalı mı yoksa bir hata mı bildirmelidir? Benzer şekilde, API Eski/Deneysel olarak işaretlenebilir. Derleyici herhangi bir tanılamayı raporlamalı, API'yi sessizce kullanmalı veya API'yi sessizce kullanmamalı mı?
Birleşim bildirimi türleri eksikse ne olur?
veya eksikse UnionAttributeIUnionIUnion<TUnion> ne olur? Hata? Sentez? Başka bir şey mi?
[Çözüldü] Genel IUnion arabiriminin tasarımı
türünden devralmaması IUnion veya parametresini IUnion<TUnion>ile sınırlamaması gereken bağımsız değişkenler yapılmıştırIUnion<TUnion>. Tekrar ziyaret etmeliyiz.
Çözünürlük: Arabirim IUnion<TUnion> şimdilik kaldırıldı.
[Çözüldü] Büyük/küçük harf türü olarak null atanabilir değer türleri ve bunların etkileşimleri TryGetValue
Yukarıdaki kurallar, bir olay türü null atanabilir bir değer türüyse, karşılık gelen TryGetValue bir yöntemde kullanılan parametre türünün temel alınan tür olması gerektiğini belirtir.
Bu, bir null değerin bu yöntemle asla verim sağlanamayacağı gerçeğiyle motive edilir. Tüketim tarafında, tür deseni olarak null atanabilir bir değer türüne izin verilmezken, temel alınan türle eşleşmenin bu yöntemin çağrısıyla eşlenebilmesi gerekir.
Bu açma işlemini kabul ettiğimizi onaylamamız gerekir.
Çözünürlük: Kabul edildi/onaylandı
Kutulama olmayan birleşim erişim deseni
Uygun HasValue ve TryGetValue API'leri bulmak için kesin kurallar belirtmeniz gerekir.
Devralma söz konusu mu? Okuma/yazma HasValue kabul edilebilir bir eşleşme mi? Vb.
[Çözüldü] TryGetValue eşleşen dönüştürmeler
Birleşim Eşleştirme bölümünde şu ifadeler yer almaktadır:
Belirli bir türün
Tdenetlenmesi anlamına gelen bir desen için, birTryGetValue(S value)yöntem varsa ve 'denTSöğesine örtük bir dönüştürme varsa, bu yöntem değeri elde etmek için kullanılır.
Örtük dönüştürme kümesi herhangi bir şekilde kısıtlanmış mı? Örneğin, kullanıcı tanımlı dönüştürmelere izin veriliyor mu? Tanımlama grubu dönüştürmeleri ve diğer önemsiz dönüştürmeler ne olacak? Bunlardan bazıları standart dönüştürmelerdir.
Yöntem kümesi TryGetValue başka bir şekilde kısıtlanmış mı? Örneğin, Birleşim Desenleri bölümü yalnızca bir olay türüyle eşleşen parametre türüne sahip yöntemlerin dikkate alındığını belirtir:
her durum türü
Tiçin birpublic bool TryGetValue(out T value)yöntem.
Açık bir yanıt almak iyi olur.
Çözünürlük: Yalnızca örtük kimlik, başvuru veya kutulama dönüştürmeleri dikkate alınır
TryGetValue ve null atanabilir analiz
Kutulanmayan erişim deseni
HasValueveyaTryGetValue(...)birleşim türünün içeriğini sorgulamak için kullanıldığında (açıkça veya desen eşleştirme yoluyla), 'ın null atanabilirlik durumunu doğrudan denetlenmiş gibiValueetkilerValue: Null durumuValuedaldatrue"null değil" olur.
Yöntem kümesi TryGetValue herhangi bir şekilde kısıtlanmış mı? Örneğin, Birleşim Desenleri bölümü yalnızca bir olay türüyle eşleşen parametre türüne sahip yöntemlerin dikkate alındığını belirtir:
her durum türü
Tiçin birpublic bool TryGetValue(out T value)yöntem.
Açık bir yanıt almak iyi olur.
Yapı birleşim türlerinin değerleriyle ilgili default kuralları netleştirme
Not: Aşağıda belirtilen varsayılan nullability kuralı kaldırılmıştır.
Not: Aşağıda belirtilen "varsayılan" iyi biçimlendirilmişlük kuralları kaldırılmıştır. İstediğimiz şeyin bu olduğunu doğrulamamız gerekir.
Nullability bölümünde şu ifadeler yer almaktadır:
Durum türlerinden hiçbirinin null atanamaz olduğu birleşim türleri için
Valuevarsayılan durum "belki null" yerine "null değil"dir.
Aşağıdaki örnekte, geçerli uygulama "null değil" olarak kabul eder Values2 :
S2 s2 = default;
struct S2 : System.Runtime.CompilerServices.IUnion
{
public S2(int x) => throw null!;
public S2(bool x) => throw null!;
object? System.Runtime.CompilerServices.IUnion.Value => throw null!;
}
Aynı zamanda , İyi biçimlilik bölümü şunları söyler:
- Varsayılan değer: Birleşim türü bir değer türüyse, varsayılan değeri değerine sahiptir
nullValue.- Varsayılan oluşturucu: Birleşim türünün null (bağımsız değişken içermeyen) bir oluşturucusunun olması durumunda, sonuçta elde edilen birleşim olarak
Valuebulunurnull.
Bunun gibi bir uygulama, yukarıdaki örnekteki null atanabilir analiz davranışıyla çelişecektir.
İyi biçimlendirilmişlük kuralları ayarlanmalı mı yoksa durumu Valuedefault "belki null" mu olmalıdır?
İkincisi ise, başlatma S2 s2 = default; null atanabilirlik uyarısı üretmeli mi?
Tür parametresinin bir birleşim türüne kısıtlanmış olsa bile hiçbir zaman birleşim türü olmadığını onaylayın.
class C1 : System.Runtime.CompilerServices.IUnion
{
private readonly object _value;
public C1(int x) { _value = x; }
public C1(string x) { _value = x; }
object System.Runtime.CompilerServices.IUnion.Value => _value;
}
class Program
{
static bool Test1<T>(T u) where T : C1
{
return u is int; // Not a union matching
}
static bool Test2<T>(T u) where T : C1
{
return u is string; // Not a union matching
}
}
Koşul sonrası öznitelikler Union örneğinin varsayılan null atanabilirliğini etkilemeli mi?
Not: Aşağıda belirtilen varsayılan nullability kuralı kaldırılmıştır. Artık birleşim oluşturma yöntemlerinden özelliğin varsayılan null atanabilirliğini Value çıkaramıyacağız. Bu nedenle, soru kullanımdan kaldırılmış/artık geçerli tasarım için geçerli değildir.
Durum türlerinden hiçbirinin null atanamaz olduğu birleşim türleri için
Valuevarsayılan durum "belki null" yerine "null değil"dir.
Aşağıdaki senaryoda uyarı bekleniyor mu?
#nullable enable
struct S1 : System.Runtime.CompilerServices.IUnion
{
public S1(int x) => throw null!;
public S1([System.Diagnostics.CodeAnalysis.NotNull] bool? x) => throw null!;
object? System.Runtime.CompilerServices.IUnion.Value => throw null!;
}
class Program
{
static void Test2(S1 s)
{
// warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive).
// For example, the pattern 'null' is not covered.
_ = s switch { int => 1, bool => 3 }; //
}
}
Birleşim dönüştürmeleri
[Çözüldü] Öncelik açısından diğer dönüştürmeler arasında nereye aitler?
Birleşim dönüştürmeleri, kullanıcı tanımlı dönüştürmenin başka bir biçimi gibi görünür. Bu nedenle, geçerli uygulama, örtük kullanıcı tanımlı bir dönüştürmeyi sınıflandırma girişimi başarısız olduktan hemen sonra bunları sınıflandırır ve mevcut olması durumunda, kullanıcı tanımlı dönüştürmenin yalnızca başka bir biçimi olarak değerlendirilir. Bunun aşağıdaki sonuçları vardır:
- Örtük kullanıcı tanımlı dönüştürme, birleşim dönüştürmeye göre önceliklidir
- Kodda açık atama kullanıldığında, açık kullanıcı tanımlı dönüştürme birleşim dönüştürmeye göre önceliklidir
- Kodda açık atama olmadığında, birleşim dönüştürmesi açık kullanıcı tanımlı dönüştürmeye göre önceliklidir
struct S1 : System.Runtime.CompilerServices.IUnion
{
public S1(int x) => ...
public S1(string x) => ...
object System.Runtime.CompilerServices.IUnion.Value => ...
public static implicit operator S1(int x) => ...
}
struct S2 : System.Runtime.CompilerServices.IUnion
{
public S2(int x) => ...
public S2(string x) => ...
object System.Runtime.CompilerServices.IUnion.Value => ...
public static explicit operator S2(int x) => ...
}
class Program
{
static S1 Test1() => 10; // implicit operator S1(int x) is used
static S1 Test2() => (S1)20; // implicit operator S1(int x) is used
static S2 Test3() => 10; // Union conversion S2.S2(int) is used
static S2 Test4() => (S2)20; // explicit operator S2(int x)
}
Beğendiğimiz davranışın bu olduğunu onaylamamız gerekiyor. Aksi takdirde dönüştürme kuralları netleştirilmelidir.
Çözünürlük:
Çalışma grubu tarafından onaylanmıştır.
[Çözüldü] Oluşturucunun parametresinin başvuru durumu
Şu anda dil yalnızca değere göre ve in kullanıcı tanımlı dönüştürme işleçleri için parametrelere izin verir.
Bu kısıtlamanın nedenleri, birleşim dönüştürmeleri için uygun oluşturucular için de geçerlidir.
Teklif:
Yukarıdaki in Union types bölümünün tanımını case type constructor ayarlayın:
-For each public constructor with exactly one parameter, the type of that parameter is considered a *case type* of the union type.
+For each public constructor with exactly one **by-value or `in`** parameter, the type of that parameter is considered a *case type* of the union type.
Çözünürlük:
Şimdilik çalışma grubu tarafından onaylandı. Ancak, durum türü oluşturucuları kümesini ve birleşim türü dönüştürmeleri için uygun oluşturucu kümesini "bölmeyi" düşünebiliriz.
[Çözüldü] Null Atanabilir Dönüştürmeler
Null Atanabilir Dönüştürmeler bölümü, temel alınan olarak kullanılabilecek dönüştürmeleri açıkça listeler. Geçerli belirtim bu listede herhangi bir ayarlama önermez. Bu, aşağıdaki senaryo için bir hatayla sonuçlanır:
struct S1 : System.Runtime.CompilerServices.IUnion
{
public S1(int x) => throw null;
public S1(string x) => throw null;
object System.Runtime.CompilerServices.IUnion.Value => throw null;
}
class Program
{
static S1? Test1(int x)
{
return x; // error CS0029: Cannot implicitly convert type 'int' to 'S1?'
}
}
Teklif:
Belirtimi, birleşim dönüştürmesi S tarafından desteklenenden örtük null atanabilir dönüştürmeyi T? destekleyecek şekilde ayarlayın.
Özellikle, birleşim türü olduğunu varsayarsakT, bir tür T? veya ifadeden E türe bir birleşim dönüştürmesi E varsa ve C bir büyük/küçük harf türündeyse Tbir türe C örtük dönüştürme vardır.
Türünün null atanamaz bir değer türü olması gerektiğini E unutmayın.
Dönüştürme, temel alınan birleşim dönüştürmesi olarak değerlendirilir ve ardından 'dan'a STT sarmalanır T?
Çözünürlük:
Onaylı.
[Çözüldü] Kaldırılan dönüşümler
Kaldırılan birleşim dönüştürmelerini desteklemek için Kaldırılan dönüşümler bölümünü ayarlamak istiyor musunuz? Şu anda bunlara izin verilmiyor:
struct S1 : System.Runtime.CompilerServices.IUnion
{
public S1(int x) => throw null;
public S1(string x) => throw null;
object System.Runtime.CompilerServices.IUnion.Value => throw null;
}
class Program
{
static S1 Test1(int? x)
{
return x; // error CS0029: Cannot implicitly convert type 'int?' to 'S1'
}
static S1? Test2(int? y)
{
return y; // error CS0029: Cannot implicitly convert type 'int?' to 'S1?'
}
}
Çözünürlük:
Şimdilik kaldırılmış birleşim dönüştürmesi yok. Tartışmadan bazı notlar:
Kullanıcı tanımlı dönüştürmelere benzetme burada biraz bozuluyor. Genel birleşimler, gelen null değeri içerebilir. Kaldırma işleminin içinde depolanan değerle
nullbirleşim türünün bir örneğini oluşturması mı yoksa değerini mi oluşturmasınullNullable<Union>gerektiği net değildir.
[Çözüldü] Temel türün bir örneğinden birleşim dönüştürmesi engellensin mi?
Geçerli davranış kafa karıştırıcı olabilir:
struct S1 : System.Runtime.CompilerServices.IUnion
{
public S1(System.ValueType x)
{
}
public S1(string x) => throw null;
object System.Runtime.CompilerServices.IUnion.Value => throw null;
}
class Program
{
static S1 Test1(System.ValueType x)
{
return x; // Union conversion
}
static S1 Test2(System.ValueType y)
{
return (S1)y; // Unboxing conversion
}
}
Dil, temel türden kullanıcı tanımlı dönüştürmelerin bildirilmesine açıkça izin vermemektedir. Bu nedenle sence'in bu şekilde birleşim dönüştürmelerine izin vermemesi gerekebilir.
Çözünürlük:
Şimdilik özel bir şey yapma. Genel senaryolar yine de tam olarak korunamaz.
[Çözüldü] Arabirim türünün bir örneğinden birleşim dönüştürmesi engellensin mi?
Geçerli davranış kafa karıştırıcı olabilir:
struct S1 : I1, System.Runtime.CompilerServices.IUnion
{
public S1(I1 x) => throw null;
public S1(string x) => throw null;
object System.Runtime.CompilerServices.IUnion.Value => throw null;
}
interface I1 { }
struct S2 : System.Runtime.CompilerServices.IUnion
{
public S2(I1 x) => throw null;
public S2(string x) => throw null;
object System.Runtime.CompilerServices.IUnion.Value => throw null;
}
class C3 : System.Runtime.CompilerServices.IUnion
{
public C3(I1 x) => throw null;
public C3(string x) => throw null;
object System.Runtime.CompilerServices.IUnion.Value => throw null;
}
class Program
{
static S1 Test1(I1 x)
{
return x; // Union conversion
}
static S1 Test2(I1 x)
{
return (S1)x; // Unboxing
}
static S2 Test3(I1 x)
{
return x; // Union conversion
}
static S2 Test4(I1 x)
{
return (S2)x; // Union conversion
}
static C3 Test3(I1 x)
{
return x; // Union conversion
}
static C3 Test4(I1 x)
{
return (C3)x; // Reference conversion
}
}
Dil, temel türden kullanıcı tanımlı dönüştürmelerin bildirilmesine açıkça izin vermemektedir. Bu nedenle sence'in bu şekilde birleşim dönüştürmelerine izin vermemesi gerekebilir.
Çözünürlük:
Şimdilik özel bir şey yapma. Genel senaryolar yine de tam olarak korunamaz.
IUnion arabiriminin ad alanı
Arabirim için IUnion ad alanı içeren ad alanı belirtilmemiş olarak kalır. Amaç bir ad alanında global tutmaksa, bunu açıkça belirtelim.
Teklif: Bu basitçe göz ardı edilen bir şeyse ad alanını kullanabiliriz System.Runtime.CompilerServices .
Tür olarak Union sınıflar
[Çözüldü] Örneğin kendisini denetleme null
Birleşim türü bir sınıf türüyse, değerin kendisi null olabilir. Peki null denetimler ne olacak?
Desen null , özelliği denetlemek Value için birlikte kabul edildi, bu nedenle birleşimin kendisinin null olmadığını nasıl denetlersiniz?
Örneğin:
- Bir yapı olduğunda
UnionS,s is nulldeğerininS?trueyalnızca kendisi olduğundasolurnull. bir sınıf olduğundaC, değerininfalseC?kendisinullolduğundac, ancaktrueckendisi olmadığındanullvec.Valueolduğunda olur.nullc is nullUnion
Başka bir örnek:
class C1 : IUnion
{
private readonly object? _value;
public C1(){}
public C1(int x) { _value = x; }
public C1(string x) { _value = x; }
object? IUnion.Value => _value;
}
class Program
{
static int Test1(C1? u)
{
// warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive).
// For example, the pattern 'null' is not covered.
// This is very confusing, the switch expression is indeed not exhaustive (u itself is not
// checked for null), but there is a case 'null => 3' in the switch expression.
// It looks like the only way to shut off the warning is to use 'case _'. Adding it removes
// all benefits of exhaustiveness checking, any union case could be missing and there would
// be no diagnostic about that.
return u switch { int => 1, string => 2, null => 3 };
}
}
Tasarımın bu bölümü, birleşim türünün bir yapı olduğu beklentisi etrafında açıkça iyileştirilmiştir. Bazı seçenekler:
- Çok kötü. Desen eşleşmesi yerine null denetiminiz için kullanın
==. - Desenin
null(ve diğer desenlerde örtük null denetiminin) hem birleşim değerine hem de özelliğine uygulanmasınaValueizin verin:u is null ==> u == null || u.Value == null. - Sınıfların birleşim türleri olmasına izin verme!
[Çözüldü] Bir Union sınıftan türetme
Bir sınıf, geçerli belirtime göre temel sınıfı olarak bir Unionsınıf kullandığında, sınıfın Unionkendisi olur. Bunun nedeni, arabirimin IUnion uygulamasını otomatik olarak "devralması" ve yeniden uygulamak için gerekli olmamasıdır. Aynı zamanda, türetilmiş türün oluşturucuları bu yeni Unioniçindeki tür kümesini tanımlar. İki sınıf etrafında çok garip bir dil davranışı elde etmek çok kolaydır:
class C1 : IUnion
{
private readonly object _value;
public C1(long x) { _value = x; }
public C1(string x) { _value = x; }
object IUnion.Value => _value;
}
class C2(int x) : C1(x);
class Program
{
static int Test1(C1 u)
{
// Good
return u switch { long => 1, string => 2, null => 3 };
}
static int Test2(C2 u)
{
// error CS8121: An expression of type 'C2' cannot be handled by a pattern of type 'long'.
// error CS8121: An expression of type 'C2' cannot be handled by a pattern of type 'string'.
return u switch { long => 1, string => 2, null => 3 };
}
}
Bazı seçenekler:
Sınıf türü bir
Uniontür olduğunda değiştirin. Örneğin, bir sınıf, tümü doğru olduğunda birUniontürdür:-
sealedBunun nedeni, türetilmiş türlerin tür olarakUniondeğerlendirilmeyerek kafa karıştırıcı olmasıdır. - Temellerinden hiçbiri uygulanmaz
IUnion
Bu hala mükemmel değil. Kurallar çok ince. Hata yapmak kolaydır. Bildirimde tanılama yoktur, ancak
Unioneşleştirme çalışmaz.-
Sınıfların birleşim türleri olmasına izin verme.
[Çözüldü] is-type işleci
is-type işleci çalışma zamanı türü denetimi olarak belirtilir. Yazımsal olarak bir tür deseni gibi görünür, ancak öyle değildir. Bu nedenle, özel Unioneşleştirme kullanılmaz ve bu da kullanıcı karışıklığına neden olabilir.
struct S1 : IUnion
{
private readonly object _value;
public S1(int x) { _value = x; }
public S1(string x) { _value = x; }
object IUnion.Value => _value;
}
class Program
{
static bool Test1(S1 u)
{
return u is int; // warning CS0184: The given expression is never of the provided ('int') type
}
static bool Test2(S1 u)
{
return u is string and ['1', .., '2']; // Good
}
}
Özyinelemeli birleşim söz konusu olduğunda tür deseni uyarı vermese de kullanıcının yapacağını düşündüğü şeyi yapmaz.
Çözünürlük: Bir tür deseni olarak çalışmalıdır.
Liste düzeni
Liste düzeni her zaman eşleşmeyle Union başarısız olur:
struct S1 : IUnion
{
private readonly object _value;
public S1(int[] x) { _value = x; }
public S1(string[] x) { _value = x; }
object IUnion.Value => _value;
}
class Program
{
static bool Test1(S1 u)
{
// error CS8985: List patterns may not be used for a value of type 'object'. No suitable 'Length' or 'Count' property was found.
// error CS0021: Cannot apply indexing with [] to an expression of type 'object'
return u is [10];
}
}
static class Extensions
{
extension(object o)
{
public int Length => 0;
}
}
Diğer sorular
- Hem birleşim dönüştürmelerinde oluşturucuların kullanımı hem de birleşim deseni eşleştirmesinin kullanımı
TryGetValue(...), birden çok tane uygulandığında yumuşak olacak şekilde belirtilir: Yalnızca birini seçerler. Bu, iyi biçimlendirilmişlük kurallarına göre önemli olmamalıdır, ancak bu konuda rahat mısınız? - Belirtim, birleşim türünün kendisinde bulunan herhangi bir
Valueözellik yerine özelliğinIUnion.Valueuygulanmasına bağımlıdır. Bu, deseni uygulamak için mevcut türler (diğer kullanımlar için kendiValueözelliğine sahip olabilir) için daha fazla esneklik sağlamak için amaçlanır. Ancak bu gariptir ve diğer üyelerin nasıl bulunduğu ve doğrudan birleşim türünde nasıl kullanıldığıyla tutarsızdır. Değişiklik yapalım mı? Diğer bazı seçenekler:- Ortak
Valuebir özelliği kullanıma açmak için birleşim türlerini zorunlu kılar. - Varsa ortak
Valuebir özelliği tercih edin, ancak yoksa uygulamaya geri dönünIUnion.Value(kurallara benzerGetEnumerator).
- Ortak
- Önerilen birleşim bildirimi söz dizimi, özellikle servis talebi türlerini ifade etme konusunda evrensel olarak sevilmez. Şu ana kadarki alternatifler de eleştirilerle karşılanır, ancak bir değişiklik yapmamız mümkündür. Geçerli olanla ilgili bazı önemli endişeler dile getirildi:
- Büyük/küçük harf türleri arasında ayırıcı olarak virgüller, sıranın önemli olduğu anlamına gelebilir.
- Parantezli listeler birincil oluşturuculara çok benzer (parametre adları olmasa da).
- Küme ayraçlarında "durumları" olan sabit listelerinden çok farklı.
- Birleşim bildirimleri tek bir başvuru alanıyla yapılar oluştururken, eşzamanlı bağlamda kullanıldığında beklenmeyen davranışlara karşı hala biraz hassastır. Örneğin, kullanıcı tanımlı işlev üyesi birden çok kez başvuruda
thisbulunursa, içeren değişken iki erişim arasındaki başka bir iş parçacığı tarafından bir bütün olarak yeniden atanmış olabilir. Derleyici gerektiğinde yerel bir konuma kopyalamakthisiçin kod oluşturabilir. Öyle mi olmalı? Genel olarak, hangi eşzamanlılık dayanıklılığı derecesi arzu edilir ve makul bir şekilde ulaşılabilir?
C# feature specifications