C#では、インターフェイスを実装すると、すべてのメンバーが暗黙的にパブリックになります。protected
アクセシビリティ修飾子(もちろん、internal
を除く)を指定できればもっと良いのではないでしょうprivate
か。それとも、代わりに抽象クラスを使用するだけでよいのでしょうか。
9 に答える
インターフェイスが内部の場合、そのすべてのメンバーはアセンブリの内部になります。ネストされたインターフェースが保護されている場合、外側のクラスのサブクラスのみがそのインターフェースにアクセスできます。
宣言しているアセンブリの外部にあるインターフェイスの内部メンバーは、宣言している外部クラスの外部にあるインターフェイスのプロテクト メンバーと同様に無意味です。
インターフェイスのポイントは、実装する型とインターフェイスのユーザーとの間の契約を記述することです。外部の呼び出し元は実装を気にするつもりはなく、実装を気にする必要はありません。これは、内部および保護されたメンバーの目的です。
基本クラスによって呼び出される保護されたメンバーの場合、抽象クラスは、基本クラスとそれらを継承するクラスの間のコントラクトを指定するための方法です。ただし、この場合、保護されたメンバーが役に立たない縮退した純粋な抽象クラス (すべてのメンバーが抽象である) でない限り、実装の詳細は通常非常に関連性があります。その場合は、インターフェイスを使用して、選択する型を実装するための単一の基本クラスを保存します。
メソッド名の前にインターフェース名を明示的に記述することで、インターフェースの実装を隠すことができます。
public interface IInterface {
public void Method();
}
public class A : IInterface {
public void IInterface.Method() {
// Do something
}
}
public class Program {
public static void Main() {
A o = new A();
o.Method(); // Will not compile
((IInterface)o).Method(); // Will compile
}
}
意味がありません。インターフェイスは、これらのメソッドとプロパティをサポートする一般の人々との契約です。抽象クラスに固執します。
ここでのすべての回答は多かれ少なかれ、それがインターフェイスのあり方であり、普遍的な公開仕様であると言っています。
これは最も議論されているスレッドです。この質問が頭に浮かんだときに SO で見つけた 2 つの優れた回答を投稿させてください。
この回答は、派生クラスのインターフェイス メンバーに対して統一されていないアクセス指定子を使用することがいかに無意味であるかの例を示しています。コードは常に技術的な説明よりも優れています。
私にとって、強制的なパブリック インターフェイス メンバーの最も厄介な点は、インターフェイス自体はアセンブリの内部にある可能性がありますが、それが公開するメンバーはパブリックでなければならないということです。Jon Skeet は、悲しいことにこれは仕様によるものだと説明しています。
これにより、メンバーの非公開定義を持つように設計されたインターフェイスがなぜ設計されなかったのかという疑問が生じます。これにより、契約を柔軟にすることができます。これは、クラスの特定のメンバーをアセンブリの外部に公開したくないアセンブリを作成する場合に非常に便利です。何故かはわからない。
インターフェイスは、すべての実装クラスが準拠する契約です。これは、彼らがそのすべてを遵守するか、またはまったく遵守しなければならないことを意味します。
インターフェイスが公開されている場合、その連絡先のすべての部分が公開されている必要があります。そうでない場合は、1 つがフレンド/内部クラスに、他のすべてに別のものが含まれることを意味します。
抽象基本クラスを使用するか、(可能で実用的な場合)インターフェイスの内部拡張メソッドを使用します。
外部アセンブリへのインターフェイスによって実装されるほとんどすべてのコードを非表示にすることができます。
interface IVehicle
{
void Drive();
void Steer();
void UseHook();
}
abstract class Vehicle // :IVehicle // Try it and see!
{
/// <summary>
/// Consuming classes are not required to implement this method.
/// </summary>
protected virtual void Hook()
{
return;
}
}
class Car : Vehicle, IVehicle
{
protected override void Hook() // you must use keyword "override"
{
Console.WriteLine(" Car.Hook(): Uses abstracted method.");
}
#region IVehicle Members
public void Drive()
{
Console.WriteLine(" Car.Drive(): Uses a tires and a motor.");
}
public void Steer()
{
Console.WriteLine(" Car.Steer(): Uses a steering wheel.");
}
/// <summary>
/// This code is duplicated in implementing classes. Hmm.
/// </summary>
void IVehicle.UseHook()
{
this.Hook();
}
#endregion
}
class Airplane : Vehicle, IVehicle
{
protected override void Hook() // you must use keyword "override"
{
Console.WriteLine(" Airplane.Hook(): Uses abstracted method.");
}
#region IVehicle Members
public void Drive()
{
Console.WriteLine(" Airplane.Drive(): Uses wings and a motor.");
}
public void Steer()
{
Console.WriteLine(" Airplane.Steer(): Uses a control stick.");
}
/// <summary>
/// This code is duplicated in implementing classes. Hmm.
/// </summary>
void IVehicle.UseHook()
{
this.Hook();
}
#endregion
}
これにより、コードがテストされます。
class Program
{
static void Main(string[] args)
{
Car car = new Car();
IVehicle contract = (IVehicle)car;
UseContract(contract); // This line is identical...
Airplane airplane = new Airplane();
contract = (IVehicle)airplane;
UseContract(contract); // ...to the line above!
}
private static void UseContract(IVehicle contract)
{
// Try typing these 3 lines yourself, watch IDE behavior.
contract.Drive();
contract.Steer();
contract.UseHook();
Console.WriteLine("Press any key to continue...");
Console.ReadLine();
}
}
インターフェイスは、メソッドにアクセス修飾子を持たないため、適切なアクセス修飾子に対してオープンのままです。これには目的があります。他のタイプが、インターフェイスに続くオブジェクトで使用できるメソッドとプロパティを推測できるようにするためです。それらに保護された/内部アクセサーを与えると、インターフェースの目的が無効になります。
メソッドにアクセス修飾子を提供する必要があることを断言する場合は、インターフェイスから除外するか、あなたが言ったように抽象クラスを使用してください。
私は C# よりも Java に精通していますが、なぜインターフェイス内にプライベート メンバーが必要なのですか? 実装を持つことはできず、実装クラスからは見えないため、役に立ちません。動作を指定するためのインターフェイスが存在します。抽象クラスを使用するよりもデフォルトの動作が必要な場合。