2015-10-09 12 views
13

は何か違いますか?引数としてのインターフェイスまたはジェネリックメソッドwhere - 違いは何ですか?</p> <pre><code>public void Method1<T>(class1 c, T obj) where T:Imyinterface </code></pre> <p>そして</p> <pre><code>public void Method2(class1 c, Imyinterface obj) </code></pre> <p>:

最初の方法を使用する利点は何ですか?

+1

私はこの場合、同じ機能を持っていると言います。 – Jonesopolis

+3

1つの違いは、汎用メソッドで回避される2番目のバージョンを呼び出すときに構造体が囲まれることです。 – Lee

+1

@Lee [this](http://stackoverflow.com/questions/63671/is-it-safe-for-structs-to-implement-interfaces)を参照してください。通常、構造体にインターフェースを継承するのは避けてください。 – Amit

答えて

3

実際には同じですが(インターフェイスパラメータを受け入れるメソッドでは、具体的なオブジェクトをインターフェイスタイプにアップキャストするという点を除いて)、わずかに異なるシナリオを検討してください。我々は、私たちの方法は、二つのインタフェースIMyInterface1IMyInterface2を実装し、それ以外のコードはコンパイルべきではないことだけでクラスを受け入れるようにしたいとしましょう:

interface IMyInterface1 { }  

interface IMyInterface2 { } 

class MyClass : IMyInterface1 { } 

public void Method1<T>(Class1 c, T obj) where T : IMyInterface1, IMyInterface2 
{ 

} 

我々はそれが二番目のパラメータだとしてインターフェイスを受け取るメソッドを作成した場合、それはので、条件を満たしていますこの例ではMyClassとIMyInterface2のように、ユーザーが1つのインターフェイスのみを実装するクラスインスタンスを送信することをユーザーが制限することはありませんが、2番目のインターフェイスは実装しません。

ユーザーはどのインターフェースを送信する必要がありますか?コンパイル時に送信する必要がある型は実際にはわかりません。

これは一般的な制約と一般的な制約を使用するのに適していますが、一方では単一のインタフェースパラメータを使用することはできません。

+0

これは私が探している答えです – Rayet

0

voidメソッドに大きな違いはありません。

public void Method1<T>(class1 c, T obj) where T : Imyinterface 

tImyinterfaceでなければなりません
public void Method2(class1 c, Imyinterface obj, Type t) 

に等しいです。

Typeをメソッドに渡す必要があり、コンパイル時にTypeにいくつかの制約を適用する必要がある場合は、汎用メソッドを使用します。

4

ジェネリックメソッドを使用すると、あなたにわずかな署名の変更で様々な可能性を提供します:

  1. public void Method1<T>(class1 c, T obj) where T:Imyinterface, new()
    これは、タイプTの新しいインスタンスをインスタンス化することができます。
  2. public T Method1<T>(class1 c, T obj) where T:Imyinterface
    これにより、必要に応じて戻り値をキャストせずにメソッドを使用できます。
  3. public void Method1<T>(class1 c, ref T obj) where T:Imyinterface
    これにより、objの参照に新しい値を付けることができます。 outにも同じです。

これらは非汎用バージョンでは不可能です。

+1

ジェネリック型のインスタンスをインスタンス化するには、制約リストに[new constraint](https://msdn.microsoft.com/en-us/library/sd2w2ew5.aspx)を追加する必要があります。そうでなければ、それはコンパイルされません –

+0

@GianPaolo - 良い点、私は少しだけ私の答えを拡大しました。 – Amit

4

前述したように、voidメソッドでは、使用方法に大きな違いはありません。

舞台裏で見てみると、汎用メソッドでは、.NETはそれを呼び出すタイプごとに別々のメソッドをコンパイルすることがわかります。これは、構造体で呼び出されたときにボクシングを避ける効果があります。

戻り値の型を使用すると大きな違いが発生します。ジェネリックバージョンで

public T Method1<T>(class1 c, T obj) where T: IMyInterface

public IMyinterface Method2(class1 c, IMyInterface obj)

、あなたは元の型を取得するので、あなたは、元の型にプロパティやメソッド(インスタンスまたは拡張)を呼び出し続けることができます。

汎用でないバージョンでは、IMyInterfaceの値が戻されるだけなので、IMyInterfaceの一部であるプロパティまたはメソッドのみを呼び出すことができます。

私の本では、これは拡張メソッドと流暢なスタイルのAPIで使用すると最も興味深いです。

public static T Move<T>(this T animal) where T : ICanMove 
{ 
    return animal; 
} 

public static T Fly<T>(this T animal) where T : ICanFly 
{ 
    return animal; 
} 

public static T Pounce<T>(this T animal) where T : ICanPounce 
{ 

    return animal; 
} 

タイガーICanMoveとICanPounceを実装し、イーグルはICanMoveとICanFlyを実装していることを考えると、私は元の型に適用される上記の拡張メソッドを呼び出すことができます。 Intellisenseは、Eagleには.Fly()および.Move()、Tigerには.Pounce()および.Move()を表示します。ここで

var birdie = new Eagle(); 

birdie 
    .Move() 
    .Fly() 
    .Move() 
    .Fly(); 

var kitty = new Tiger(); 

kitty 
    .Move() 
    .Pounce() 
    .Move() 
    .Pounce(); 

あなたは非包括的に動かし実施された場合、それは次のようになります。

public static ICanMove Move<T>(this ICanMove animal) 
{ 
    return animal; 
} 

をICanMoveインタフェースが返されるので、コンパイラはそれが元々イーグルや虎だったという考えを持っていませんしたがって、ICanMoveインターフェイスの一部である拡張機能、メソッド、またはプロパティのみを使用できます。

関連する問題