🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C#

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

Q&A

解決済

3回答

1458閲覧

「独習C# 第3版」第9章 理解度チェック6の解答例についての疑問

guijiu

総合スコア36

C#

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

0グッド

1クリップ

投稿2019/11/16 05:16

前提

 ハーバート・シルト著「独習C# 第3版」で独習しています。
章末の練習問題の解答例に疑問を感じ質問します。
設題はこうです。

p361 第9章理解度チェック 第6問

 次に示すVehicleクラスのインターフェースを作成しなさい。
(ヒント)このでのプロパティは読み取りと書き込みが可能である必要があります。インターフェイスのプロパティには、アクセス修飾子をつけることができません。

C#

1 class Vehicle:IVehicle 2 { 3 // プロパティ 4 public int Passengers { get; protected set; } // 乗車定員 5 public int FuleCap { get; protected set; } // 燃料 6 public int Mpg { get; protected set; } // 燃費 7 8 // コンストラクタ 9 public Vehicle(int p, int f, int m) 10 { 11 this.Passengers = p; 12 this.FuleCap = f; 13 this.Mpg = m; 14 } 15 // メソッド 16 public int Range() 17 { 18 return this.FuleCap * this.Mpg; 19 } 20 21 public double FuelNeeded(int miles) 22 { 23 return (double)miles / this.Mpg; 24 } 25 }

解答例は次のとおりです。

C#

1 interface IVehicle 2 { 3 // プロパティ 4 int Passengers { get; set; } // 乗車定員 // Vehicleクラスのsetは、protectedのため setは削除 5 int FuleCap { get; set; } // 燃料 // 同上 6 int Mpg { get; set; } // 燃費 // 同上 7 // メソッド 8 int Range(); 9 double FuelNeeded(int miles); 10 }

発生している問題・エラーメッセージ

 以上、二つのソースコードをコンパイラにかけると、次のようにエラーを発生します。

エラー CS0277 'Vehicle' はインターフェイス メンバー 'IVehicle.Passengers.set' を実装しません。 'Vehicle.Passengers.set' は public ではありません。

 このエラーが発生理由は理解しています(インターフェイスはアクセス修飾子がpublicでなければならず、そのインターフェイスを継承するクラスなどもpublicで継承しなければならが、VehicleクラスがプロパティのPassengers、FuleCap、Mpgのsetアクセサのアクセス修飾子をprotectedにしているため)。

疑問点

このエラーを解消する方法は、いくつあるのでしょうか?
特にVehicleクラス側でprotectedの機能を生かした状態で、対処する方法はないでしょうか?
ご教示の程、よろしくお願いします。

試したこと

このエラーを解消するために私の試した方法は次の通り、IVehicleインターフェイス側のプロパティからsetアクセサを削除する方法です。

C#

1 interface IVehicle 2 { 3 // プロパティ 4 int Passengers { get; } // 乗車定員 // Vehicleクラスのsetは、protectedのため setは削除 5 int FuleCap { get; } // 燃料 // 同上 6 int Mpg { get; } // 燃費 // 同上 7 // メソッド 8 int Range(); 9 double FuelNeeded(int miles); 10 }

しかし、これをすると各プロパティに値をセットし忘れる恐れがあるから、あまりいい方法とわ思えません。

補足情報(FW/ツールのバージョンなど)

win8.1
Microsoft Visual Studio Community 2019 Version 16.3.9
Microsoft .NET Framework Version 4.7.2

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

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

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

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

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

guest

回答3

0

しかし、これをすると各プロパティに値をセットし忘れる恐れがあるから、あまりいい方法とわ思えません。

原則的に「インスタンスに必須な値はコンストラクタで受け取る」ように実装すれば済むと思います。ですので、「試したこと」で示しているinterfaceの書き方で良いように思います。

(あとは「乗員は乗り降りするだろうからメソッドから変更可能にしとこう」とか、「燃費はほぼほぼ固定だろうしインスタンス生成以降は不変となるように実装しよう」とか、そんなことは考え付きそうですね。)

投稿2019/11/16 07:20

tor4kichi

総合スコア769

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

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

guijiu

2019/11/16 07:30

言われる通りですね。このプロパティはコンストラクタで与えることを前提にしているので、インターフェイスからsetを削るのが正しそうですね。 ありがとうございます。
guest

0

ベストアンサー

学習する順序やコードを書く手順が、interface のほうが class より後になってるから誤解しやすいですが、
実際には 仕様(interfaceも仕様の一部) ありきです。
普通は仕様に基づきプログラミングしているはずなので、

このエラーを解消する方法は、いくつあるのでしょうか?

仕様に合ってない部分を直す一手です。
class が間違ってないことが前提なら interface を直すだけです。

「しかし、これをすると各プロパティに値をセットし忘れる恐れ…」
これは実装(classを記述)する時に考慮すべきことで interface には関係ありません。

投稿2019/11/16 06:32

hihijiji

総合スコア4152

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

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

hihijiji

2019/11/16 06:35

ちなみに Visual Studio だとクラスを右クリックしてクイックリファクタリングで クラスからインターフェイスの抽出が簡単にできます。
guijiu

2019/11/16 07:00

面白い機能があるのですね。 ありがとうございます。
guijiu

2019/11/16 07:07

本題に戻りますが、貴殿の言われることは、実装を優先するなら、インターフェイスのsetを削れということでしょうか? (プロパティをいじられたくなければ、setのないインターフェース(仕様)を作って、必要であればprotectedでsetを追記するのが、正しいような気がしてきました。)
Zuishin

2019/11/16 07:13

クラスとインターフェースが異なるなら、そもそも設計が間違っています。それを合わせるために機械的にどちらかを変えるのは、間違いに間違いを重ねるだけです。
hihijiji

2019/11/16 07:19

本来はインターフェイスに set を入れるかどうかは仕様で決まっているはずなのです。 でも仕様が解らなくて、実装が仕様通りであるなら実装に合わせるしかないですよね。 そういった疑問自体は学習段階でのみ発生する疑問なので、あまり深く考えなくて良いと思います。
guijiu

2019/11/16 07:24

zuishinさん、hihijijiさん、お二方の言われるとおりですね。初学者の要らぬ深追いですね。
Zuishin

2019/11/16 07:27

回答者全員に低評価つけているのは質問者さんですか?
guijiu

2019/11/16 07:34

低評価を付けていないとは思いますが、、、 何か操作を間違えているのでしょうか?
guest

0

インターフェースを変えるかクラスを変えるかの二種類に加えて、Passengers を明示的に実装する三種類だと思います。

追記

クラスを継承するなら new 演算子による隠蔽が使えるかもしれません。

どの方法も試してないので実際できるかどうかは保証しません。

追記

以下に対する回答です。クラスからインターフェースを作成せよという問題から派生した疑問なので、実装ではなく設計段階での修正という認識です。

実用で言えば、クラスとインターフェースのメソッドのシグネチャを違うものにしたいという疑問はを無意味です。同じものにしてください。

このエラーを解消する方法は、いくつあるのでしょうか?
特にVehicleクラス側でprotectedの機能を生かした状態で、対処する方法はないでしょうか?

投稿2019/11/16 05:21

編集2019/11/16 07:10
Zuishin

総合スコア28669

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

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

Zuishin

2019/11/16 06:48

誰だ無言で低評価つけまくってるのは。
guijiu

2019/11/16 07:11

’’’ interface IVehicle { int Passengers { get; set; } // 乗車定員 // Vehicleクラスのsetは、protectedのため setは削除 int FuleCap { get; set; } // 燃料 // 同上 int Mpg { get; set; } // 燃費 // 同上 // 満タン時の走行可能距離を計算 int Range(); double FuelNeeded(int miles); } abstract class Vehicle0 : IVehicle { public int Passengers { get; set; } // 乗車定員 public int FuleCap { get; set; } // 燃料 public int Mpg { get; set; } // 燃費 // 満タン時の走行可能距離を計算 public abstract int Range(); public abstract double FuelNeeded(int miles); } class Vehicle : Vehicle0 { public new int Passengers { get; protected set; } // 乗車定員 public new int FuleCap { get; protected set; } // 燃料 public new int Mpg { get; protected set; } // 燃費 // コンストラクタ public Vehicle(int p, int f, int m):base() { this.Passengers = p; this.FuleCap = f; this.Mpg = m; } // 満タン時の走行可能距離を計算 public override int Range() { return this.FuleCap * this.Mpg; } public override double FuelNeeded(int miles) { return (double)miles / this.Mpg; } } ’’’
guijiu

2019/11/16 07:15

1.newで隠ぺい 上記のコードのように、IvehicleとVehicleの間に抽象クラスVehicle0を追加しました。 貴殿の言われているnewで隠ぺいとは、こういうことでしょうか?
Zuishin

2019/11/16 07:16

方法がいくつあるか問われたので、実用的かどうか無関係に考えられる可能性をあげただけです。
guijiu

2019/11/16 07:17

2.「Passengers を明示的に実装」とは? 貴殿の言われる「Passengers を明示的に実装」の「明示的に実装」とはどういうことでしょうか? 改めてご教示いただければ幸いです。
Zuishin

2019/11/16 07:19

実用上は、設計が悪いので、そこからやり直すべきです。set を public にすべきでないならインターフェースから削ってください。必要ならクラスの方を変えてください。
Zuishin

2019/11/16 07:19

それともこれは知的好奇心からの疑問ですか? どちらかはっきりさせてもらえなければ答えられません。
guijiu

2019/11/16 07:27

ご教示、ありがとうございます。 おかげでabstractの使い方も理解できました。
Zuishin

2019/11/16 07:33

やっぱりいつもの人か。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問