Son zamanlarda sağlayıcılarla epeyce çalışıyorum ve soyut bir statik yöntem olan soyut bir sınıfa sahip olmak istediğim ilginç bir durumla karşılaştım. Konuyla ilgili birkaç gönderi okudum ve bu bir anlam ifade etti, ancak güzel bir açıklama var mı?
Son zamanlarda sağlayıcılarla epeyce çalışıyorum ve soyut bir statik yöntem olan soyut bir sınıfa sahip olmak istediğim ilginç bir durumla karşılaştım. Konuyla ilgili birkaç gönderi okudum ve bu bir anlam ifade etti, ancak güzel bir açıklama var mı?
Yanıtlar:
Statik yöntemler bu şekilde somutlaştırılmaz , sadece nesne referansı olmadan kullanılabilirler.
Statik bir yönteme çağrı, bir nesne başvurusu aracılığıyla değil, sınıf adı aracılığıyla yapılır ve bunu çağırmak için Ara Dil (IL) kodu, soyut yöntemi, onu tanımlayan sınıfın adıyla çağırır; kullandığınız sınıf.
Bir örnek göstereyim.
Aşağıdaki kodla:
public class A
{
public static void Test()
{
}
}
public class B : A
{
}
B.Test'i çağırırsanız, şöyle:
class Program
{
static void Main(string[] args)
{
B.Test();
}
}
Sonra Main yöntemi içindeki gerçek kod aşağıdaki gibidir:
.entrypoint
.maxstack 8
L0000: nop
L0001: call void ConsoleApplication1.A::Test()
L0006: nop
L0007: ret
Gördüğünüz gibi, A.Test çağrısı yapılır, çünkü kodu bu şekilde yazabilseniz bile, onu tanımlayan A sınıfıdır ve B.Test'e değil.
Eğer olsaydı sınıf türlerini bir değişken bir tip değil bir nesneye atıfta yapabilirsiniz Delphi, olduğu gibi, (aynı zamanda ve kurucular) sanal ve dolayısıyla soyut statik yöntemleri için daha fazla kullanılmasını olurdu, ancak bunlar mevcut değildir ve dolayısıyla statik aramalar .NET'te sanal değildir.
IL tasarımcılarının kodun B.Test'i çağırması için derlenmesine izin verebileceğini ve çağrıyı zamanında çözmesini sağlayabileceğini anlıyorum, ancak yine de orada bir tür sınıf adı yazmak zorunda kalacağınız için sanal olmayacaktır.
Sanal yöntemler ve dolayısıyla soyut olanlar, yalnızca çalışma zamanında birçok farklı türde nesne içerebilen bir değişken kullandığınızda yararlıdır ve bu nedenle değişkende bulunan geçerli nesne için doğru yöntemi çağırmak istersiniz. Statik yöntemlerle yine de bir sınıf adından geçmeniz gerekir, bu nedenle çağrılacak kesin yöntem derleme zamanında bilinir çünkü değişemez ve değişmez.
Bu nedenle, sanal / soyut statik yöntemler .NET'te kullanılamaz.
Test()
içindedir A
soyut ve potansiyel tanımlanan olmaktan ziyade B
\.
Car
sanal bir statik ile türünü CreateFromDescription
daha sonra, bir kabul kod fabrika yöntemiyle Car
-constrained genel tür T
diyebiliriz T.CreateFromDescription
türde bir araba üretmek için T
. Böyle bir yöntemi tanımlayan her tip, sanal "statik" yöntemleri tutan iç içe bir sınıf jenerikinin statik tekil bir örneğini taşıyorsa, böyle bir yapı CLR içinde oldukça iyi bir şekilde desteklenebilir.
Statik yöntemler miras alınamaz veya geçersiz kılınamaz ve bu yüzden soyut olamazlar. Statik yöntemler bir sınıfın örneğinde değil türünde tanımlandığından, bu tür üzerinde açıkça çağrılmalıdır. Bu nedenle, alt sınıftaki bir yöntemi çağırmak istediğinizde, onu çağırmak için adını kullanmanız gerekir. Bu kalıtımı ilgisiz kılar.
Bir an için statik yöntemleri devralabileceğinizi varsayın. Bu senaryoyu düşünün:
public static class Base
{
public static virtual int GetNumber() { return 5; }
}
public static class Child1 : Base
{
public static override int GetNumber() { return 1; }
}
public static class Child2 : Base
{
public static override int GetNumber() { return 2; }
}
Base.GetNumber () öğesini çağırırsanız, hangi yöntem çağrılır? Hangi değer geri döndü? Nesnelerin örnekleri oluşturmadan kalıtımın oldukça zor olduğunu görmek oldukça kolaydır. Mirassız soyut yöntemler sadece bedeni olmayan yöntemlerdir, bu yüzden çağrılamazlar.
int DoSomething<T>() where T:Base {return T.GetNumber();}
. DoSomething<Base>()
Beş, DoSomething<Child2>()
iki ise geri dönecek olsaydı faydalı olurdu. Bu yetenek sadece oyuncak örnekleri için değil, aynı zamanda class Car {public static virtual Car Build(PurchaseOrder PO);}
türetilmiş her sınıfın Car
bir satın alma emri verilen bir örneği oluşturabilecek bir yöntem tanımlaması gerektiği gibi bir şey için de yararlı olacaktır.
Başka bir katılımcı (McDowell), polimorfizmin sadece nesne örnekleri için çalıştığını söyledi. Nitelikli olmalı; sınıfları "Sınıf" veya "Metaclass" türünün örnekleri olarak gören diller vardır. Bu diller hem örnek hem de sınıf (statik) yöntemler için polimorfizmi destekler.
C #, önceki Java ve C ++ gibi, böyle bir dil değildir; static
Anahtar kelime yöntemi statik olarak bağlı ziyade dinamik sanal / tutulmasının belirtilmesi açıkça kullanılmaktadır.
İşte statik alanlar ve yöntemler için kesinlikle mirasa ihtiyaç duyulan bir durum:
abstract class Animal
{
protected static string[] legs;
static Animal() {
legs=new string[0];
}
public static void printLegs()
{
foreach (string leg in legs) {
print(leg);
}
}
}
class Human: Animal
{
static Human() {
legs=new string[] {"left leg", "right leg"};
}
}
class Dog: Animal
{
static Dog() {
legs=new string[] {"left foreleg", "right foreleg", "left hindleg", "right hindleg"};
}
}
public static void main() {
Dog.printLegs();
Human.printLegs();
}
//what is the output?
//does each subclass get its own copy of the array "legs"?
legs
statik bir soyut özellik olmalıdır.
Önceki açıklamalara eklemek için, statik yöntem çağrıları derleme zamanında belirli bir yönteme bağlıdır , bu da polimorfik davranışı dışlar.
Aslında statik yöntemleri (delphi'de) geçersiz kılıyoruz, biraz çirkin, ama ihtiyaçlarımız için iyi çalışıyor.
Bunu sınıfların sınıf örneği olmadan kullanılabilir nesnelerinin bir listesini alabilmesi için kullanıyoruz, örneğin, şöyle görünen bir yöntemimiz var:
class function AvailableObjects: string; override;
begin
Result := 'Object1, Object2';
end;
Bu çirkin ama gerekli, bu şekilde tüm sınıfların sadece mevcut nesneleri aramak için anlık hale getirilmesi yerine, sadece gerekli olanı başlatabiliriz.
Bu basit bir örnektir, ancak uygulamanın kendisi tüm sınıfları tek bir sunucuda ve sunucunun sahip olduğu her şeye ihtiyaç duymayabilecek ve asla bir nesne örneğine ihtiyaç duymayacak birden fazla farklı istemciye sahip bir istemci-sunucu uygulamasıdır.
Bu, her istemci için farklı bir sunucu uygulamasına sahip olmaktan çok daha kolaydır.
Umarım örnek açıktır.
Soyut yöntemler dolaylı olarak sanaldır. Soyut yöntemler bir örnek gerektirir, ancak statik yöntemlerin bir örneği yoktur. Yani, soyut bir sınıfta statik bir yöntem olabilir, sadece statik soyut (ya da soyut statik) olamaz.