質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

2回答

997閲覧

【c#】拡張メソッドでもインスタンスメソッドのように多態性を実現したい

Fuyu1221

総合スコア1

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

1グッド

1クリップ

投稿2022/11/10 05:24

編集2022/11/10 05:43

前提

同じインターフェイスを継承したクラスがあります。
そのクラス群に対してそれぞれ拡張メソッドを実装したのですが、
インターフェイスに対しての拡張メソッドを参照してしまい多態性を実現できません。

C#

1 public interface InterFace {} 2 3 public class A : InterFace {} 4 public class B : InterFace {} 5 6 public static class Extension 7 { 8 public static string func(this InterFace i) {return "インターフェイス";} 9 public static string func(this A a) {return "クラスA";} 10 public static string func(this B a) {return "クラスB";} 11 } 12 13 public class Program 14 { 15 public static void test<T>(T t) where T : InterFace 16 { 17 //InterFaceに実装されている拡張メソッドが呼び出されてしまう。 18 Console.WriteLine(t.func()); //出力 : インターフェイス 19 } 20 }

実現したいこと

インスタンスメソッドのように拡張メソッドを使いたいです。
実際のコードではClass A・B には触れないので直接メソッドを追加できない状態です。
if文・switch文などで条件分岐を設定するしかないのでしょうか?

Bongo👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2022/11/10 05:30

多様性というのは多態性のことですか? 実メソッドは拡張メソッドに優先されるので、InterFace 以外の拡張メソッドをやめ、そのメソッドをクラスに実装すればいいと思います。
Fuyu1221

2022/11/10 05:42 編集

多態性の事です。誤字ってました... 実際はUnityでのコードなのですが、クラスA・BはUnity標準クラスなので直接クラスを追加できないため拡張メソッドを使用していました。
Zuishin

2022/11/10 05:53 編集

拡張メソッドはむやみに使うものではありません。それらのクラスを引数とするメソッドを作るのが良いと思います。 この質問に書いてあることが事実なら、拡張メソッドにしなければならない場合は、実行時に分岐する他ないでしょう。 実際に行いたいことによっては、もっと良い方法がありそうな気配を感じます。 しかし本来、引数の優先度が高いメソッドの方が優先して呼ばれるはずです。タイポなど何かそれを妨げる要素がないか確認してみてください。
Fuyu1221

2022/11/10 06:35

UnityのAPI互換レベルがデフォルトだと.NET Standard2.1なのでdynamicを使用するとコンパイルエラーが出てしまう為、.NET Frameworkに変更して試してみたところ動作しました!
Kerupim

2022/11/10 08:22

一応Unity限定の注意点ですが、dynamic はセキュリティの都合上、特定のハードウェアで 動作しないのでご注意ください。 ※ビルドはできても、実行時にエラーになります。
guest

回答2

0

Fuyu1221さんはわかっておられると思いますが、閲覧者にはわかりにくいので回答しておきます。
c# - Polymorphism Through Extension Methods? - Stack Overflow

cs

1interface I { string Func() => "I Func"; } 2class A : I { public string Func() => "A Func"; } 3class B : I { public string Func() => "B Func"; } 4class C : I { } 5 6static class Extensions 7{ 8 public static string Ex(this I i) => "I Ex"; 9 public static string Ex(this A a) => "A Ex"; 10 public static string Ex(this B b) => "B Ex"; 11 12 public static string Dynamic(this I i) => Dynamic((dynamic)i); 13 // !!private!! publicだと全部これが呼ばれて台無し 14 private static string Dynamic<T>(this T t) where T : I => "I Dynamic"; 15 public static string Dynamic(this A a) => "A Dynamic"; 16 public static string Dynamic(this B b) => "B Dynamic"; 17} 18 19class Program 20{ 21 static void Main() 22 { 23 Func(new A()); 24 Func(new B()); 25 Func(new C()); 26 Console.WriteLine(); 27 28 Ex(new A()); 29 Ex(new B()); 30 Ex(new C()); 31 Console.WriteLine(); 32 33 Dynamic(new A()); 34 Dynamic(new B()); 35 Dynamic(new C()); 36 } 37 38 static void Func<T>(T t) where T : I => Console.WriteLine(t.Func()); 39 static void Ex<T>(T t) where T : I => Console.WriteLine(t.Ex()); 40 static void Dynamic<T>(T t) where T : I => Console.WriteLine(t.Dynamic()); 41}
A Func B Func I Func I Ex I Ex I Ex A Dynamic B Dynamic I Dynamic

投稿2022/11/10 08:30

TN8001

総合スコア9321

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

https://paiza.io/projects/ugXW9USPdpGHidBQhvZaSw

何かの間違いです。
確かめたところ、ちゃんとクラスの方の拡張メソッドが呼ばれています。

なお、IInterface 型の変数に代入した場合にインターフェースの方の拡張メソッドが呼ばれるのは、メソッドがオーバーライドされていないので、そういうものです。
test の型引数がインターフェースになっている可能性があるので、test<A>(a) のように呼んでみましょう。

投稿2022/11/10 06:04

編集2022/11/10 06:17
Zuishin

総合スコア28660

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2022/11/10 06:54

そうですね。 そこで定義されているのは、IInterface への拡張メソッドと、Class1 への拡張メソッドの二つです。 そして Class1 が IInterface を実装しているかどうかに関わらず、同じ拡張メソッドを定義できます。 それは単に同名のメソッド(オーバーロード)であり、オーバーライドされたものではありません。 私も読み間違えていましたが、Where を無くすとコンパイルエラーになることからわかるように、Test 中で使われているのは IInterface の方のオーバーロードです。 dynamic を使うような実行時の手当てが許されるのであれば、Interface の方の拡張メソッドだけ残し、その中で分岐するのが良いと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問