2009-03-13 20 views
13

Birisi bu davranışı Generics'te açıklayabilir mi? C# Genel işlevler

ben denetlemenin bir "Denetim olan TextBox" türü yapıyorum switch case kullanabilir, Yan not C#

protected virtual void LoadFieldDataEditor <T> (ref T control, string strFieldName) where T : Control 
{ 
    //T can be different types of controls inheriting from System.Web.UI.Control 
    if (control is TextBox) 
    { 
    //This line gives an error 
    //((TextBox)control).Text = "test"; 

    //This line works! 
    (control as TextBox).Text = "Test"; 
    } 
} 

bir jenerik fonksiyonu var?

DÜZENLEME:

Maalesef hata mesajı eklemek unuttum! İşte

gitmek:

Error 3 Cannot convert type 'T' to 'TextBox' 

DÜZENLEME:

biz jenerik söz ederken, bir sorum daha var. Oldukça zor olan yöntem başka genel tür

protected virtual void LoadFieldDataEditor <T1, T2> (T1 control, T2 objData, string strFieldName) where T1 : Control where T2 : BaseDataType 
{ 
    //I will need to access field1. 
    //I don't know at compile time if this would be SomeType1 or 
//SomeType2 but all of them inherit from BaseDataType. 

    //Is this possible using generics? 
} 

public abstract class BaseDataType {} 

public class SomeType1 : BaseDataType 
{ 
    string field1; 
    string field2; 
} 
+0

Bir hatanın ne anlama geldiğini sorduğunuzda, hatanın ne olduğunu söylemek gerçekten yararlıdır. Sadece şimdi yeniden üretmeye çalışıyorum ... –

+0

Hata nedir? –

+0

@Jon Skeet: Lanet ... Durumda olduğunun farkında değildim ... –

cevap

21

bir genel tür dönüştürülebilir için ne kurallar içerecek şekilde genişletilmiştir

, (Ben yeni yazı başlatmak olsaydı emin değildi) ve bazen bu durumda olduğu gibi, sezgisel olarak. Detaylar için C# özelliğinin 6.2.6 bölümüne bakınız. Laker olabilecekleri yerler var ve bence bu onlardan biri. Siz 'u object'a kadar dökülebilir ve sonra tekrar aşağı, ama bu çirkin.

Bu durumda daha iyi bir çözüm olacaktır:

Her şey bir yana bir yana
protected virtual void LoadFieldDataEditor <T> (ref T control, 
               string strFieldName) 
    where T : Control 
{ 
    TextBox textBox = control as TextBox; 
    if (textBox != null) 
    { 
     textBox.Text = "test"; 
    } 
} 

, bu sadece iki yerine tek bir yürütme zamanı kontrol gerektirir.

Yan not için: hayır, türlerde anahtar/kasa kullanamazsınız. (Bu adı alabilir ve üzerinde geçiş yapabilirsiniz, ancak bu korkunç olurdu.)

+0

Bu yöntemde yeni bir textBox oluşturuyorsunuz. Bu metnin değişmesi, param olarak gönderilen metni değiştiriyor mu (ref Control)? – DotnetDude

+0

Hayır, bu yöntem yeni bir TextBox oluşturmuyor. Hangi satırı yeni bir tane oluşturuyorsunuz? Ben kesinlikle kontrol tarafından ref geçme gerek yok şüpheleniyorum ... –

+0

Ben bu satırı düşündüm - TextBox textBox = TextBox olarak kontrol; yeni bir metin kutusu oluşturdu. Benim "geçerimden geçerim" üzerine fırçalamak ve ref kavramlarını geçmek zorunda kalabilirim. Benim anlayışım, değere (yani, ref olmadan) geçiş yaptığınız zaman, yeni bir bellek konumunda yeni bir varyasyon yaratır ve kaynak değerini kopyalar – DotnetDude

1

İlk satır derleyici hatası veriyor: "T türünü TextBox'a dönüştüremiyor." Bu tür bir döküm sadece derleyicinin, başlangıç ​​sınıfını bitiş sınıfına dönüştürmenin mümkün olduğunu bilmesi durumunda yasaldır. T bir şey olabileceği için, derleyicinin bilmesinin bir yolu yoktur. Çalışma zamanında kontrol etseniz bile, bu derleyiciyi rahatlatmaz. İkinci tür yayınlar tamam, çünkü oyuncu çalışmazsa null değerini döndürecek. DÜZENLEME: Tuinstoel'in belirttiği gibi, döküm kuralları benim tarif ettiğimden daha karmaşıktır. @rossfabricant'a karşı olarak

+0

Cevabımıma bakın. – tuinstoel

0

.

Bu çok basit değil, ilk yöntem derleme, ikinci değil.

void Test(Control control) 
{ 
    if (control is TextBox) 
    { 
     ((TextBox)control).Text = "test"; 
    } 
} 

void Test<T>(T control) where T : Control 
{ 
    if (control is TextBox) 
    { 
     ((TextBox)control).Text = "test"; 
    } 
} 
3

Çok bu olmaya üstlenmeden öneririm:

birkaç açıklamalarda belirtildiği gibi
protected virtual void LoadFieldDataEditor(Control control, string strFieldName) 

, bu yöntem hiç Generics'i ihtiyacı yoktur.

Bir Denetime sınırlandığınız için, temel sınıfı ve bunun bir referans türü olduğunu biliyorsunuz (Denetim), böylece jenerik ve ref parametre bildirimlerinden kaçınabilirsiniz.

Denetim bir başvuru türü olduğu için, yöntemdeki özelliklerini değiştirmekte serbestsiniz ve bu doğru şekilde çalışacaktır. Ayar .Text, vb, yapmaya çalıştığınız şeyi tam olarak yapacak, ancak çok daha basit olacak.

Orada olması gereken olabilir küçük bir şanstır:

protected virtual void LoadFieldDataEditor(ref Control control, string strFieldName) 

ancak yöntem içinde kontrolünü yeniden atamak için gittiğini, bu sadece gerekli olacaktır (yani: control = new TextBox();). Bunu yapmamaya şiddetle tavsiye ederim, çünkü beklenmedik bazı davranışlara neden olabilir ve açık olmayacaktır. Yeni bir kontrol oluşturmaya çalışıyorsanız, bir çıkış parametresi kullanarak ya da sadece yeni kontrole geri dönmek, her şeyi daha net hale getirecektir. Ayrıca, genel olarak, bunları dahil etmek için iyi bir neden olmadığı sürece genel yöntemlerden kaçınmak iyi bir fikirdir. FxCop ekibi, uzun vadede kodu daha az anlaşılır kılmaya eğilimli oldukları için kullanımlarını caydırmaya çalışan bazı kurallar ekledi (ve daha sonra çıkardı). Jenerik yöntemleri kullanmanın birçok iyi nedeni vardır, ancak bu onların kullanımını gerektirmez, bu yüzden onlardan kaçınmanızı tavsiye ederim.

+0

Açıklama için teşekkürler. Metin atama sadece soruyu sormak amacıyla yapıldı. Gerçekte, başka pek çok şeyim var. Ama evet, ref kullanmamak için refactor yaptım ve harika çalışıyor! Teşekkürler – DotnetDude