2009-03-13 14 views
13

ジェネリックスでこの動作を説明できる人はいますか? C#Generics関数

は、私は私がチェックする「コントロールでテキストボックス」タイプをやっているスイッチケースを使用することができ、サイドノートでは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"; 
    } 
} 

での一般的な機能を持っていますか?

編集:

エラーメッセージを追加する忘れました!

ここに行く:

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

EDIT:私たちはジェネリックについて話している間

を、私は別の質問を持っています。かなりトリッキーです方法は、他の一般的なタイプ

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

エラーが何を意味するのかを尋ねるときは、エラーの内容を伝えることが非常に役立ちます。ちょうど今再現しようとしています... –

+0

何がエラーですか? –

+0

@Jon Skeet:くそー...私はあなたが事件にあったとは思わなかった... –

答えて

21

ジェネリック型をに変換することができます何のためのルールを含むように拡張されました

、(私は新しいポストを開始しなければならなかった場合は確認されませんでした)この場合のように時には直観に反している。詳細については、C#仕様のセクション6.2.6を参照してください。彼らが不快になる可能性がある場所があります、そして、私はこれが彼らの一つだと思います。 にキャストアップし、objectにキャストしてからもう一度ダウンしますが、それは醜いです。

は、この場合、よりよい解決策は、次のようになります。

何か別に
protected virtual void LoadFieldDataEditor <T> (ref T control, 
               string strFieldName) 
    where T : Control 
{ 
    TextBox textBox = control as TextBox; 
    if (textBox != null) 
    { 
     textBox.Text = "test"; 
    } 
} 

は、これが唯一の代わりに2の単一の実行時間のチェックが必要です。

サイドノートの場合:いいえ、タイプにはスイッチ/ケースを使用できません。 (型名を取得してスイッチを入れることはできますが、恐ろしいことです)

+0

このメソッドで新しいtextBoxを作成しています。これでテキストを変更すると、パラメータ(ref control)として送信されたテキストが変更されますか? – DotnetDude

+0

いいえ、このメソッドは新しいTextBoxを作成しません。あなたは新しいラインを作成すると思いますか?私は強く、あなたが実際に参照によってコントロールを渡す必要はないと強く疑う。 –

+0

私はこの行と思った - TextBox textBox = TextBoxとしてのコントロール。 が新しいテキストボックスを作成しました。私は私の "val by pass"をブラッシュアップし、ref概念を渡さなければならないかもしれません。私の理解は、新しいメモリ位置に新しいvarを作成し、ソース値をコピーすることで値渡し(つまり、refなし)するときでした。 – DotnetDude

1

最初の行は、「TをTextBoxに変換できません」というコンパイラエラーを示しています。この種のキャストは、コンパイラが開始クラスを終了クラスに変換することが可能であることが分かっている場合にのみ有効です。 Tは何でもかまいませんので、コンパイラが知る方法はありません。実行時にチェックしているにもかかわらず、これはコンパイラを安らかにしません。 2番目の種類のキャストはOKです。なぜなら、キャストが機能しない場合はnullを返すだけだからです。 編集:tuinstoelが指摘するように、キャストのルールは、私が記述したよりも複雑です。

+0

私の応答を参照してください。 – tuinstoel

0

@rossfabricantへの回答です。

それほど単純ではありません。最初の方法はコンパイルされ、2番目の方法はコンパイルされません。

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

私は非常にこのとしてリファクタリングお勧めします:いくつかのコメントで述べたように

protected virtual void LoadFieldDataEditor(Control control, string strFieldName) 

、この方法は、すべてのジェネリックを必要としません。

コントロールに制約があるので、リファレンスクラス(Control)であるため、ジェネリックとrefパラメータの宣言を避けることができます。

Controlは参照型なので、メソッドのプロパティを自由に変更できます。これは正しく動作します。 .Textなどの設定は、あなたがやろうとしていることを正確に行いますが、ずっと簡単です。

そこにはそれがあることを必要とすることができる小さなチャンスです:

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

は、しかし、あなたはあなたのメソッド内のコントロールを再割り当てするつもりだった場合にのみ必要とされるであろう(すなわち:control = new TextBox();)。非常に予期しない動作を引き起こす可能性があり、明らかではないので、そうしないことを強くお勧めします。新しいコントロールを作成しようとしている場合、outパラメータを使用するか、新しいコントロールを返すだけで、すべてのことがはっきりします。

また、一般的には、一般的な方法を避けることが望ましい理由がない限り、避けることをお勧めします。 FxCopチームは、長期的にはコードを理解しにくくする傾向があるため、使用を妨害しようとするいくつかのルールを追加(および後で削除)しました。ジェネリックメソッドの使用には多くの理由がありますが、使用する必要はありませんので、避けることをおすすめします。

+0

ありがとうございます。テキストを割り当てることは、質問することのみを目的としていました。実際には、他にもたくさんのことが起こっています。しかし、はい、私はrefを使わないようにリファクタリングしました。ありがとう – DotnetDude