2011-01-11 22 views
23

Bir yapıya uzantı yöntemleri ekleyebilir misiniz?Bir yapıda uzantı yöntemleri

+7

Yapıya bir uzantı yöntemi eklemeye çalıştınız mı? Onlara cevabı bulduğunuzda soruları silmemeniz gerektiğini unutmayın, diğerleri aynı şeyi merak edebilir. Ve evet, onları ilan edebilirsin, ama yapının değişmesini beklemedikçe, yapının içindeki şeyleri değiştirmeyi beklediğin gibi çalışmayacaksın. –

+1

Evet denedim ama işe yaramadı. –

+1

Çalıştığımıza teşekkür ederim, benim hatam –

cevap

18

Evet, yapılara uzantı yöntemleri ekleyebilirsiniz. Uzatma yöntemi tanımına göre, bunu kolayca elde edebilirsiniz. Aşağıda,

+17

Yaptığınız gibi, struct, VALUE (uzantılar yapmak istediği gibi) uzantı yöntemine geçirilirken buna dikkat edin. Bu nedenle, uzantı yönteminde yapıda yaptığınız tüm değişiklikler kaybolacaktır - tabi ki yapısını döndürmediğiniz sürece (ve daha sonra bu yapılandırılmış bir yapıyla, örneğin yeniden atamak gibi) bir şey yapmazsanız. Bir yapı üzerinde bir uzantı yöntemi yapmanın ve referans olarak geçirilmemenin bir yolu yoktur (C#). – BrainSlugs83

+0

Aynı zamanda bir yapı olan ve Serializable ve ComVisible ve TypeConverter ile dekore edilen System.Drawing.Rectangle'i genişletemem gibi görünüyor. – zionpi

17

'da uzantı yönteminin örneği Yapılara uzantı yöntemleri eklemek mümkündür, ancak önemli bir uyarı vardır. Normal yapı yöntemleri yöntemleri, parametresini ref parametresi olarak kabul eder, ancak C# bunu yapan uzantı yöntemleri tanımlamasına izin vermez. this mutasyonuna neden olan yapısal yöntemler biraz tehlikeli olabilir (derleyici yapı yöntemlerinin salt okunur yapılar üzerinde çağrılmasına izin vereceğinden, ancak this değerini değer olarak geçirebileceğinden), aynı zamanda zaman zaman onların da sadece uygun bağlamlarda kullanılır.

Bu arada, vb.net, uzantı yöntemlerinin, ByRef parametresi olarak this parametresini kabul etmesine izin verir; sınıf, yapı veya bilinmeyen kategori genelidir. Bu, arayüzlerin yapılarla uygulanabileceği bazı durumlarda yardımcı olabilir. Örneğin, List<string>.Enumerator türünde this türünde IEnumerator<string> türünde bir parametre kullanan bir uzantı yöntemini çağırmayı deniyorsa veya IEnumerator<string> için kısıtlanmış bir jenerik parametresiyle this parametresini alırsa ve yöntem sayımı ilerletmeye çalışırsa, yöntem döndüğünde herhangi bir ilerleme geri alınacaktır. Kısıtlı bir jenerik referansı alan bir uzatma yöntemi, ancak, (vb.net'de mümkündür) gerektiği gibi davranacaktır.

+1

Peki, C# 'da bir örnek kullanmanın bir örneği ne olabilir? 'public static Rect CreateRectFromPercents (bu Rect rect)' örneğin çalışmıyor. – MichaelTaylor3D

+0

@ MichaelTaylor3D: 'Rect' nedir? System.Drawing.Rectangle' veya bazı özel türler mi demek istiyorsunuz? – supercat

+0

benim api im'in bir parçası olan bir yapı. Sadece örnek olarak kullanıyordum. API, doğrudan değiştirmeyi engelliyor, dolayısıyla bir uzantı yöntemini kullanmayı umuyordum. Yapıları için mümkün olduğunu okudum ama henüz bir örnek görmedim. Senin açıklaman en yakın bulabildiğim. – MichaelTaylor3D

2

Evet, bir struct/value türünde bir uzantı yöntemi tanımlayabilirsiniz. Ancak, referans türlerinde uzatma yöntemleri ile aynı davranışı yoktur. Örneğin, aşağıdaki C# kodundaki GetA() uzantı yöntemi, yapının bir referansı değil, yapının kopyasını alır,. Bu, bir yapıda C# uzantısı yönteminin özgün yapı içeriğini değiştiremeyeceği anlamına gelir.

public static class TestStructExtensionMethods { 
    public struct FooStruct { 
     public int a; 
    } 
    public static int GetA(this FooStruct st) { 
     return st.a; 
    } 
} 

Yapı içeriğini değiştirmek için, struct parametresinin "ref" olarak bildirilmesi gerekir. Ancak, "bu ref" C# 'ye izin verilmez.

' This is efficient, because it is handed a reference to the struct 
<Extension()> _ 
Public Sub GetA(ByRef [me] As FooStruct) As Integer 
    Return [me].a 
End Sub 

' It is possible to change the struct fields, because we have a ref 
<Extension()> _ 
Public Sub SetA(ByRef [me] As FooStruct, newval As Integer) 
    [me].a = newval 
End Sub 
: özgün yapı değiştirebilir böylece

// this works, but is inefficient, because it copies the whole FooStruct 
// just to return a 
public static int GetA(ref FooStruct st) { 
    return st.a; 
} 

VB.NET, sen, ByRef yapı uzantısı yöntemi olarak bu oluşturabilirsiniz: Yapabileceğimiz en iyi statik bir uzantı olmayan yöntemi gibidir

+0

Bu VB.NET, uzatma yöntemlerinin yapıları 'ref' iyi bir şey olarak kabul etmesine izin verir, ancak VB'nin "ref" tarafından geçilemeyen şeyleri sessizce kopyalayacağı ve kopyaları asıllar yerine geçireceği için. VB.NET'e bunu yapmamanın bir yolu olsaydı (kod bunun yerine derlemeyi reddederdi), bu gibi uzantı yöntemleri, 'bunu değiştiren yapı örneği yöntemlerine semantik olarak üstündür. MS'nin neden derleyici tarafından oluşturulan geçici yapılar üzerinde başlatılabilir olup olmadıklarını gösterebilecek yöntemleri sağlama nedenini bilmiyorum. – supercat

+0

"... ama VB'nin sessizce aktarılamayan şeyleri kopyalayıp orijinalleri değil kopyaları geçeceği için" - VB bunu ne zaman yapıyor? - "byref", C# 'de "ref" ile aynı IL koduna kadar derlenmiştir. Anlayışım, herhangi bir şeyin .NET tarafından ref ile geçirilebilmesidir - kopyalanan tek şey, değer türleridir (ve yalnızca ref tarafından geçilmiyorlar). – BrainSlugs83

+0

@ BrainSlugs83: VB.net'de referans olarak bir okuma/yazma özelliğini geçmeyi deneyin. Bu özellik, bir değişken değil, getter fonksiyonunun dönüş değeridir ... dolayısıyla referans olarak geçmez. C# buna izin vermez. VB bunun yerine, değeri kopyalayarak ve referans ile * kopyasını * geçirerek, referansla geçecek ve ardından işlev döndüğünde, özelliği yeni değere ayarlayacaktır. Hangi * çoğunlukla * çalışır ve LoD'yi takip ederseniz ve yapıları değişmez tutabilseniz, özellikleri yarı saydam olarak işler ve tutar, ancak alt nesneler ve değişken değer türleri dahil olduğunda yarı-şaşırtıcı şekillerde kırılabilir. – cHao

5

Gelecek Google çalışanları (ve Bingers) için, bir yapıyı genişletmek için bazı kodlar verilmiştir. Bu örnek, değeri double türüne dönüştürür. Eğer ToString() kullanmak gibi Bundan sonra

public static class ExtensionMethods { 

    public static double ToDouble<T>(this T value) where T : struct { 
     return Convert.ToDouble(value); 
    } 
} 

sen ToDouble() kullanabilirsiniz. Taşmalar gibi dönüşüm öğelerine dikkat edin.

İlgili konular