2009-04-05 18 views
30

Bir C# yönteminin iki aşırı yüklenmiş sürümüne sahip olduğumu varsayalım:C#: Aşırı yüklenen yönteme null - hangi yöntem denir?

void Method(TypeA a) { } 
void Method(TypeB b) { } 

Yöntemi şu şekilde adlandırıyorum:

Method(null); 

Yöntemin aşırı yüklenmesi nedir? Belirli bir aşırı yükün çağrıldığından emin olmak için ne yapabilirim?

+0

diğeri çağırabilir. –

cevap

67

TypeA ve TypeB'a bağlıdır. bunların tam bir geçerli ise, arama geçerli bir yapılacaktır

  • (bir değer türü ama TypeA başvuru türü olduğu için, örneğin TypeB için null hiçbir dönüşüm yoktur). Aksi takdirde TypeA ve TypeB arasındaki ilişkiye bağlıdır.
    • sonra TypeA kullanarak aşırı yük kullanılacaktır TypeA den TypeB bir örtük dönüştürme ama TypeBTypeA ila örtülü hiçbir dönüşüm yoksa.
    • sonra TypeB kullanarak aşırı yük kullanılacaktır TypeB den TypeA bir örtük dönüştürme ama TypeATypeB ila örtülü hiçbir dönüşüm yoksa.
    • Aksi takdirde, arama belirsizdir ve derlenemez.

bak Bölüm detaylarını öğrenmek için C# 3.0 spec 7.4.3.4.

İşte bunun bir örneği belirsiz değil. Burada TypeB, TypeA türetilmiştir, yani TypeB ile TypeA arasındaki örtük bir dönüşüm var, ancak bunun tersi de doğru değil. Böylece TypeB kullanılarak aşırı kullanılır: Genel olarak

using System; 

class TypeA {} 
class TypeB : TypeA {} 

class Program 
{ 
    static void Foo(TypeA x) 
    { 
     Console.WriteLine("Foo(TypeA)"); 
    } 

    static void Foo(TypeB x) 
    { 
     Console.WriteLine("Foo(TypeB)"); 
    } 

    static void Main() 
    { 
     Foo(null); // Prints Foo(TypeB) 
    } 
} 

, hatta bir başka şekilde belirsiz çağrı karşısında belirli bir aşırı yük kullanıldığından emin olmak için, sadece döküm:

Foo((TypeA) null); 

veya

Foo((TypeB) null); 

Bu, bildirme sınıflarında kalıtımı içeriyorsa (yani, bir sınıf, temel sınıfı tarafından bildirilen bir yöntemi aşırı yüklüyorsa), başka bir soruna girdiğiniz ve argümandan ziyade yöntemin hedefini yayınlamak.

+0

@Jon: Neden açıkladığınız bir dönüşümde açıkladığınız gibi davranışı kullanabilirsiniz? Tam tersini beklemeyi tercih ederim. Bu sadece bir tanım meselesi mi? –

+2

@divo: Bu kesinlikle bir tasarım kararı, ancak muhtemelen arkasındaki sebebi, TypeB metodunun oldukça özel bir TypeA yöntemi olduğu yönündedir. Yani, her geçerli arg için, nesne TypeB olduğu bilinmedikçe, varsayılan olarak TypeA eşleştirilecektir. Boş için bu davranış, bu tutarlılığı sağlar. –

+0

Mehrdad haklı - eğer TypeB'den TypeA'ya dönüştürebilirsiniz, o zaman TypeB TypeA'dan daha spesifiktir, bu yüzden tercih edilir. –

1

muazzam çağrı. (derleme zamanı hatası).

+0

Merhaba, Aşağıdaki örneği denedim ve derleme hatası almadım; herhangi bir düşünce neden? sınıf Programı { geçersiz test1 (ıcollection a) { Console.WriteLine ("test1-ıcollection"); } void test1 (IList a) { Console.WriteLine ("test1-List"); } statik geçersiz Ana (string [] hatalar) { Program p = new Program(); p.test1 (null); Console.ReadKey(); } } –

+0

ama tip IComparer sınıf Programı { geçersiz test1 bir parametreyi kabul etmek aşırı birini değişince ben hatayı derlemek (ılist a) { Console.WriteLine ("test1- var Liste"); } void test1 (IComparer a) { Konsolu.WriteLine ("Test1-IComparer"); } statik geçersiz Ana (string [] hatalar) { Program p = new Program(); p.test1 (null); Console.ReadKey(); } } –

8

Jon Skeet kapsamlı bir yanıt verdi, ancak tasarım bakış açısından, derleyici teknik özelliklerinin köşe durumlarına bağlı olmamalıdır. Başka bir şey yoksa, yazmadan önce ne olduğunu araştırmak zorunda kalırsanız, onu okumayı denecek bir sonraki kişi ne yaptığını bilmeyecektir. Bakılabilir değil.

Aşırı yükler kolaylık sağlamak için var ve aynı adı taşıyan iki farklı aşırı yük aynı şeyi yapmalıdır. İki yöntem farklı şeyler yaparsa, bunlardan birini veya her ikisini yeniden adlandırın.

Çok sayıda parametreli değişkenlere ve aşırı duyarlılık sağlamak için daha az parametreli aşırı yüklenmeye sahip aşırı yüklü bir yöntem için daha alışılageldik.

örn. string ToString(string format, System.IFormatProvider provider)
string ToString(System.IFormatProvider provider) varsayılan bir biçim sağlayan, çoğu parametreleri vardır ve
string ToString() varsayılan bir biçim ve sağlayıcıyı,

+0

Aşırı yüklerle ilgili noktanızı göremiyorum. Doğru, aşırı yüklenmeler aynı şeyi yapmalıdır, ancak bunu farklı şekillerde yapabilir. Bu yüzden aşırı yüklenme istiyorsun. Bağımsız değişkenlerin sayısı ilgisizdir ve aynı veya farklı olabilir (örnek olarak: çeşitli dönüştürme yöntemleri). Derleyici özelikleri hakkında: Bir sonraki kişinin beceri düzeyine bağlı olarak, her şey bir “köşe durumu” olabilir. Tasarımınız mantıklı olduğu ve sezgisel şekilde çalıştığı sürece, bu iş yapıyor. Bu, sınıfın daha sonra kullanılması durumunda değil, tasarımın dikkatli bir şekilde dikkate alınmasını gerektirebilir. –

+0

Yaptığım nokta, aşırı yüklenmelerin en tipik kullanımının, farklı tipler içerebilecek veya daha fazla veya daha az parametre içerebilen veriler üzerinde bazı işlevler gerçekleştirmesi olduğunu düşünüyorum. Aslında, daha az sayıda parametreli gerçekte daha az farklı parçadaki tüm aynı verilere (dizelere) sahip bir sürü aşırı yük yazdım. Bu durumda parçaları parçalara ayırarak ve tekrar sağladıklarında daha yüksek aşırı yükleri çağırırlar. –

0

basit bir çözüm imzası ile başka bir yöntemi yaratmaktır besler:

void Method() { } 

veya Olması gereken yöntemlerden birinin üzerindeki imzayı güncellemek daha iyidir:

void Method(TypeB b = null) { } 

ve sonra böylece t: Çekirdeği

Method(); 

değeri null Türlenmemiş ve bu nedenle derleyici yöntemi imzaları biriyle yetişemediğinden olup. Çalışma zamanında, null'a dönüşebilecek herhangi bir değişken yazılmaya devam eder ve bu nedenle bir soruna neden olmaz.

3

Jon Skeet, varsayılan olarak hangi aşırı yüklenmenin seçildiğini zaten yanıtladı; ancak, belirli bir aşırı yükün söz konusu olduğundan emin olmak istiyorsanız, genellikle, adlandırılmış parametrelerin, dökümden daha iyi kullanılması önerilir.

Eğer varsa:

void Method(TypeA a) { } 
void Method(TypeB b) { } 

En az bir yöntem params anahtar sözcüğünü kullanan yöntemleri aşırı farkında olmak Method(a: null); veya Method(b: null);

İlgili konular