"Özel Sınıf" tam olarak nedir?


114

Derlemek için aşağıdaki gibi bir şey elde edemedikten sonra:

public class Gen<T> where T : System.Array
{
}

hata ile

Bir kısıtlama özel bir sınıf `` System.Array '' olamaz

Ben, tam olarak ne merak başladı olan bir "özel sınıf"?

İnsanlar genellikle System.Enumgenel bir kısıtlamada belirttiklerinde aynı türden bir hata alıyor gibi görünmektedir . Birlikte aynı sonuçları aldık System.Object, System.Delegate, System.MulticastDelegateve System.ValueTypede.

Daha fazlası var mı? C # 'da "özel sınıflar" hakkında herhangi bir bilgi bulamıyorum.

Ayrıca, hangi olduğu bir genel tür kısıtlaması olarak kullanabilirsiniz olamayacağını bu sınıflara kadar özel?


14
Bunun doğrudan bir kopya olduğunu sanmıyorum. Soru "bunu neden bir kısıtlama olarak kullanamıyorum" değil, "bu özel sınıflar nelerdir". Bu sorulara bir göz attım ve onlar sadece "özel sınıf" ın gerçekte ne olduğunu ve neden özel kabul edildiğini açıklamadan, kısıtlama olarak kullanmanın neden yararsız olacağını açıkladılar.
Adam Houldsvvorth

2
Tecrübelerime göre, kullanılan ancak onları doğrudan kullanamayacağınız, yalnızca örtük olarak diğer sözdizimi yoluyla kullanamayacağınız sınıflar özel sınıflardır. Enum aynı kategoriye girer. Onları tam olarak neyin özel kıldığını bilmiyorum.
Lasse V.Karlsen

@AndyKorneyev: Bu soru biraz farklı. "Özel sınıf" tanımını ve / veya bunların kapsamlı bir listesini istiyorum. Bu soru, System.Array'in genel bir tür kısıtlaması olamama nedenini sorar.
Mints97

Gönderen belgelerinde bu "[...] sadece sistem ve derleyiciler Array sınıfından açıkça türetebilirsiniz." Belirtmektedir. Muhtemelen onu özel bir sınıf yapan şey budur - derleyici tarafından özel olarak ele alınır.
RB.

1
@RB .: yanlış. Anlamına gelecektir Bu mantık System.Objectolduğunu değil : Bu geçerli olduğu gibi, bir "özel sınıf" public class X : System.Object { }, ama System.Objecthala bir "özel sınıf" tır.
Mints97

Yanıtlar:


106

Roslyn kaynak kodundan, kodlanmış türlerin bir listesi gibi görünür:

switch (type.SpecialType)
{
    case SpecialType.System_Object:
    case SpecialType.System_ValueType:
    case SpecialType.System_Enum:
    case SpecialType.System_Delegate:
    case SpecialType.System_MulticastDelegate:
    case SpecialType.System_Array:
        // "Constraint cannot be special class '{0}'"
        Error(diagnostics, ErrorCode.ERR_SpecialTypeAsBound, syntax, type);
        return false;
}

Kaynak: Binder_Constraints.cs IsValidConstraintType
Bunu GitHub araması kullanarak buldum: "Bir kısıtlama özel sınıf olamaz"


1
@kobi 702, derleyici çıktısında (bu sorunun alıntılaması ihmal edilmiştir) ve diğer yanıtlarda görüldüğü gibi derleyici hatası CS0702 olur.
AakashM

1
@AakashM - Teşekkürler! Derlemeye çalıştım ve herhangi bir nedenle hata numarasını alamadım. Daha sonra öğrenmem neredeyse 5 dakikamı aldı ve yorumumu düzenlemek için yeterli zamanım olmadı. Üzücü bir hikaye.
Kobi

1
@Kobi: Çıktı penceresine bakmanız gerekiyor , orada tam derleyici hata kodu numarasını bulacaksınız CS0702.
Tim Schmelter

9
Öyleyse şimdi asıl soru, neden bu özel sınıflar?
David, Monica'yı Yeniden

@DavidGrinberg Belki de nedeni bu türlerden doğrudan (hariç object) miras alamamanız veya en azından bununla bir ilgisi olmasıdır. Ayrıca where T : ArrayAssay'in T olarak geçmesine de izin verir, ki bu muhtemelen çoğu insanın istediği şey değildir.
IllidanS4, Monica'yı

42

Neden olduğu: Ben de benzer bir soru üzerine 2008 yılından bir Jon Skeet yorum bulunamadı System.Enumkısıt değil destekledi.

Bunun biraz konu dışı olduğunu biliyorum ama Eric Lippert'e (C # ekibi) sordu ve şu yanıtı verdiler:

Öncelikle, varsayımınız doğrudur; kısıtlamalar üzerindeki kısıtlamalar, CLR kadar değil, dilin büyük eserleridir. (Bu özellikleri yapsaydık, CLR'de numaralandırılabilir türlerin nasıl belirtildiğine ilişkin değiştirmek istediğimiz birkaç küçük şey olurdu, ancak çoğunlukla bu dil çalışması olurdu.)

İkincisi, kişisel olarak temsilci kısıtlamalarına, numaralandırma kısıtlamalarına ve bugün yasa dışı olan kısıtlamaları belirleme yeteneğine sahip olmayı çok isterim çünkü derleyici sizi kendinizden kurtarmaya çalışıyor. (Yani, kapalı türleri kısıtlama olarak yasal hale getirmek vb.)

Ancak, zamanlama kısıtlamaları nedeniyle, bu özellikleri büyük olasılıkla dilin bir sonraki sürümüne aktaramayacağız.


10
@YuvalItzchakov - Github \ MSDN'den alıntı yapmak daha mı iyi? C # ekibi konu veya benzeri bir konu hakkında somut bir cevap verdi ... Bu gerçekten kimseye zarar veremez. Jon Skeet az önce onlardan alıntı yaptı ve C #'a geldiğinde oldukça güvenilir.
Amir Popovich

5
Üzülmene gerek yok. Bunun geçerli bir cevap olmadığını söylemedim :) Sadece jonskeet olan vakıf hakkındaki düşüncelerimi paylaşmak mıydı; p
Yuval Itzchakov

40
FYI BTW Sanırım orada alıntı yaptığın benim. :-)
Eric Lippert

2
@EricLippert - Bu, alıntıyı daha da güvenilir kılar.
Amir Popovich

Yanıttaki bağlantı alanı öldü.
Pang

25

MSDN'ye göre bu, statik bir sınıf listesi:

Derleyici Hatası CS0702

Kısıtlama özel sınıf 'tanımlayıcı' olamaz Aşağıdaki tipler kısıtlama olarak kullanılamaz:

  • System.Object
  • System.Array
  • System.Delegate
  • System.Enum
  • System.ValueType.

4
Harika, doğru cevap gibi görünüyor, iyi bul! Ama System.MulticastDelegatelistede neresi var ?
Mints97

8
@ Mints97: hiçbir fikrim yok, belki belge eksikliği?
Tim Schmelter

Bu sınıflardan da miras alamayacaksın gibi görünüyor.
David Klempfner

14

C # 4.0 Dil Spesifikasyonuna göre (Kodlanmış: [10.1.5] Tip parametresi kısıtlamaları) iki şeyi anlatır:

1] Tür, nesne olmamalıdır. Tüm türler nesneden türetildiği için, böyle bir kısıtlamaya izin verilseydi hiçbir etkisi olmazdı.

2] T'nin birincil kısıtlaması veya tür parametresi kısıtlaması yoksa, etkin temel sınıfı nesnedir.

Genel bir sınıf tanımladığınızda, istemci kodunun sınıfınızı başlatırken tür bağımsız değişkenleri için kullanabileceği tür türlerine kısıtlamalar uygulayabilirsiniz. İstemci kodu, bir kısıtlama tarafından izin verilmeyen bir tür kullanarak sınıfınızı başlatmaya çalışırsa, sonuç bir derleme zamanı hatasıdır. Bu kısıtlamalara kısıtlamalar denir. Kısıtlamalar, where bağlamsal anahtar sözcüğü kullanılarak belirtilir. Genel bir türü başvuru türü olarak sınırlamak istiyorsanız, şunu kullanın: class.

public class Gen<T> where T : class
{
}

Bu, jenerik türün int veya yapı vb. Gibi bir değer türü olmasını engeller.

Ayrıca, Kısıtlama özel sınıf 'tanımlayıcısı' olamaz. Aşağıdaki türler kısıtlama olarak kullanılamaz:

  • System.Object
  • System.Array
  • System.Delegate
  • System.Enum
  • System.ValueType.

12

Çerçevede, kendilerinden türetilen tüm türlere etkin bir şekilde özel nitelikler aktaran ancak bu özelliklere sahip olmayan belirli sınıflar vardır . CLR'nin kendisi, bu sınıfların kısıtlama olarak kullanılmasına karşı herhangi bir yasak getirmez, ancak bunlarla sınırlı olan genel türler, somut türlerin yapacağı gibi miras alınmayan özellikleri edinmez. C # yaratıcıları, bu tür davranışların bazı insanların kafasını karıştırabileceğinden ve bunun için herhangi bir fayda göremedikleri için, CLR'de yaptıkları gibi davranmalarına izin vermek yerine bu tür kısıtlamaları yasaklamaları gerektiğine karar verdiler.

Örneğin, birinin yazmasına izin verildiyse void CopyArray<T>(T dest, T source, int start, int count):; Bir geçmek mümkün olur destve sourcetip bir bağımsız değişken beklemek yöntemlere System.Array; bundan başka, bir derleme doğrulama bu alacağı destve sourceuyumlu bir dizi tipleri, ama biri kullanılarak dizi erişim elemanlarına mümkün olmaz []operatör.

Kullanım yetersizlik Arraybir kısıtlama olarak, çünkü çoğunlukla oldukça kolay bir çözüm sağlamaktır void CopyArray<T>(T[] dest, T[] source, int start, int count)eski yöntem çalışacak neredeyse tüm durumda irade çalışması. Bununla birlikte, bir zayıflığı vardır: önceki yöntem System.Array, bağımsız değişkenlerin uyumsuz dizi türleri olduğu durumları reddederken , bağımsız değişkenlerden birinin veya her ikisinin de türde olduğu senaryoda çalışır ; Her iki argümanın da türde olduğu bir aşırı yük eklemek System.Array, kodun kabul etmesi gereken ek durumları kabul etmesine neden olur, ancak aynı zamanda olmaması gereken durumları da yanlışlıkla kabul etmesine neden olur.

Özel kısıtlamaların çoğunu yasadışı ilan etme kararını rahatsız edici buluyorum. Sıfır anlamsal anlama sahip olan tek şey, System.Object[çünkü bu bir kısıtlama olarak yasal olsaydı, herhangi bir şey onu tatmin ederdi]. System.ValueTypeMuhtemelen pek kullanışlı olmayacaktır, çünkü türden referanslar ValueTypedeğer türleriyle pek ortak noktaya sahip değildir, ancak Düşünme ile ilgili durumlarda makul bir şekilde bir değeri olabilir. Hem System.Enumve System.Delegatebazı gerçek kullanımlara olurdu, ancak C # yaratıcıları onları düşünmüyordu beri onlar sebepsiz yasadışı ediyoruz.


10

Aşağıdakiler CLR'de C # 4th Edition aracılığıyla bulunabilir:

Birincil Kısıtlamalar

Bir tür parametresi, sıfır birincil sınırlamayı veya bir birincil kısıtlamayı belirtebilir. Birincil kısıt, mühürlenmemiş bir sınıfı tanımlayan bir referans türü olabilir. Aşağıdaki özel başvuru türlerinden birini belirtemezsiniz: System.Object , System.Array , System.Delegate , System.MulticastDelegate , System.ValueType , System.Enum veya System.Void . Bir başvuru türü kısıtlaması belirlerken, derleyiciye belirtilen tür bağımsız değişkeninin aynı türde veya kısıtlama türünden türetilmiş bir türde olacağına söz veriyorsunuz.


Ayrıca bakınız: C # LS bölüm 10.1.4.1: Bir sınıf türü doğrudan taban sınıfı aşağıdaki türlerden olmamalıdır: System.Array, System.Delegate, System.MulticastDelegate, System.Enum, veya System.ValueType. Ayrıca, genel bir sınıf bildirimi System.Attributedoğrudan veya dolaylı temel sınıf olarak kullanılamaz.
Jeroen Vannevel

5

"Özel sınıflar" / "özel türler" için herhangi bir resmi tanım olduğunu sanmıyorum.

"Normal" türlerin anlambilimiyle kullanılamayan aa türleri hakkında düşünebilirsiniz:

  • onları doğrudan örnekleyemezsiniz;
  • özel türü doğrudan onlardan devralamazsınız;
  • onlarla çalışmak için bazı derleyici sihirleri var (isteğe bağlı olarak);
  • örneklerinin doğrudan kullanımı en azından işe yaramaz (isteğe bağlı olarak; yukarıda jenerik oluşturduğunuzu hayal edin, hangi genel kodu yazacaksınız?)

Not: Listeye eklerim System.Void.


2
System.Voidgenel bir kısıtlama olarak kullanıldığında tamamen farklı bir hata veriyor =)
Mints97

@ Mints97: doğru. Ama soru "özel" ile ilgiliyse, o zaman evet, voidçok özeldir. :)
Dennis

@Dennis: Bir türden birkaç parametresi kısıtlanmış olan kod, verileri birinden diğerine taşımak System.Arraygibi yöntemleri kullanabilir Array.Copy; bir türden parametrelere sahip kod , bunlar üzerinde System.Delegatekullanılabilir ve sonucu uygun türe çevirebilir . Genel olarak bilinen bir türün etkili bir şekilde kullanılması, böyle her tür için Yansıtma'yı bir kez kullanacaktır, ancak genel bir yöntem, genel olmayan bir yöntemden 10 kat daha hızlı olabilir. Delegate.CombineEnumHasAnyFlag
supercat
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.