2011-01-11 19 views
23

構造体に拡張メソッドを追加できますか?構造体の拡張メソッド

+7

構造体に拡張メソッドを追加しようとしましたか?あなたはそれらに答えを見つけるときに質問を削除してはならないことに注意してください、他の人は同じことについて疑問に思うかもしれません。そして、はい、それらを宣言することはできますが、構造体の変更は、それが動作しないことを期待しない限り、期待通りに機能しません。 –

+1

ええ、私は試してみましたが、うまくいきませんでした。 –

+1

ありがとう、私の欠陥 –

答えて

18

はい、構造体に拡張メソッドを追加できます。拡張メソッドの定義に従って、簡単に達成できます。以下はintの拡張メソッドの例です

namespace ExtensionMethods 
{ 
    public static class IntExtensions 
    { 
     public static bool IsGreaterEqualThan(this int i, int value) 
     { 
      return i >= value; 
     } 
    } 
} 
+17

しかし、構造体が拡張メソッドBY VALUEに渡されるので、これに注意してください(構造体がしたいように)。したがって、構造体を返さない限り(そしてそれを元の構造体に渡して、それ自身に再割り当てするなどして)、拡張メソッドの構造体に加えた変更はすべて失われます。 構造体に対して拡張メソッドを実行し、参照渡しする方法はありません(C#)。 – BrainSlugs83

+0

構造体であり、SerializableとComVisibleとTypeConverterで装飾されたSystem.Drawing.Rectangleを拡張できないようです。 – zionpi

17

構造体に拡張メソッドを追加することは可能ですが、重要な注意点があります。通常の構造体メソッドのメソッドはthisrefのパラメータとして受け付けますが、C#ではこれを行う拡張メソッドの定義を許可しません。 thisを変更するstructメソッドは、コンパイラによって構造体メソッドが読み込み専用構造体で呼び出され、thisが値渡しされるため、やや危険ですが、それらが確実に存在するように注意すると便利な場合もあります適切なコンテキストでのみ使用されます。

なお、vb.netでは、拡張メソッドがByRefというパラメータとして、thisを受け入れることができます。これは、クラス、構造体、または不明なカテゴリのジェネリックであるかどうかに関係なく適用されます。これは、インタフェースが構造体によって実装される場合に役立ちます。例えば、型List<string>.Enumeratorの変数に対して、IEnumerator<string>型のthisパラメータを受け取るか、またはIEnumerator<string>に制限された汎用の値thisを引数とする拡張メソッドを呼び出すと、メソッドが列挙子を前進しようとすると、メソッドが返ってくると、どんな進歩も取り消されます。ただし、参照によって制約付きジェネリックを取る拡張メソッド(vb.netで可能)は、必要に応じて動作します。

+1

C#で1つ使用する例は何ですか? 'public static Rect CreateRectFromPercents(このRect rect)'などは動作しません。 – MichaelTaylor3D

+0

@ MichaelTaylor3D: 'Rect'とは何ですか?あなたは 'System.Drawing.Rectangle'やカスタムタイプを意味しますか? – supercat

+0

私のAPIの一部である構造体です。私は例として使っていました。 apiは私にそれを直接変更させないようにするので、私は拡張メソッドを使うことを望んでいました。私は構造体の可能性を読んだが、私はまだ例を見てhavnt。あなたの説明は私が見つけることができる最も近いです。 – MichaelTaylor3D

2

はい、構造体/値型に対して拡張メソッドを定義できます。ただし、参照型の拡張メソッドと同じ動作をしません。

たとえば、次のC#コードのGetA()拡張メソッドは、構造体への参照ではなく、コピーの構造体を受け取ります。つまり、構造体のC#拡張メソッドは元の構造体の内容を変更できません。

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

構造体の内容を変更するには、struct paramaterを "ref"として宣言する必要があります。ただし、C#では "このref"は許可されていません。

' 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 
:私たちができる最善のような静的な非拡張メソッドである:それは、元の構造体を修正することができるように

VB.NETで
// 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; 
} 

、あなたは、ByRefの構造体の拡張メソッドとしてこれを作成することができます

+0

そのVB。NETは拡張メソッドが 'ref'によって構造体を受け入れることを可能にしますが、VBは' ref'で渡せないものを静かにコピーし、元のものの代わりにコピーを渡すという事実のためには良いことです。 VB.NETにそうしないよう指示する方法があれば(そのコードはコンパイルを拒否しなければならない)、そのような拡張メソッドは、 'this'を変更するstructインスタンスメソッドより意味的に優れています。私は、MSがコンパイラが生成した一時構造上で呼び出し可能かどうかを示す方法が何であるかを示す手段を提供していないのはなぜか分かりません。 – supercat

+0

"...しかし、VBが自動的にrefで渡すことができないものをコピーし、オリジナルの代わりにコピーを渡すということは、VBがいつそうするのでしょうか? - "byref"はC#で "ref"と同じILコードにコンパイルされています - 私の理解は、.NETでrefで渡すことができることです - コピーされるのは値の型だけです彼らはrefによって渡されません)。 – BrainSlugs83

+0

@ BrainSlugs83:VB.netで参照によって読み取り/書き込みプロパティを渡してみてください。そのプロパティは単に変数ではなくゲッター関数の戻り値です。参照渡しは機能しません。 C#はそれを許可しません。代わりに、VBは値をコピーし、* copy *を参照渡しで参照渡しを行います。関数が返ってくると、プロパティを新しい値に設定します。 LoDに従って構造体を変更することはできませんが、サブオブジェクトや変更可能な値の型が関わっている場合は、半驚くべき方法で破損する可能性があります。 – cHao

5

将来のGoogle社員(およびBingers)のために、構造体を拡張するためのコードがいくつかあります。この例では、値をdoubleタイプに変換します。この後

public static class ExtensionMethods { 

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

あなたがToString()を使用するようにあなたはToDouble()を使用することができます。オーバーフローなどのコンバージョンアイテムには注意してください。

関連する問題