C#の明示的なインターフェイスメンバーへの安全でシンプルなアクセス
-
03-10-2019 - |
質問
C#で明示的なインターフェイス実装を使用している場合、そのインターフェイスのメンバーにアクセスするために、そのインターフェイスの1つにオブジェクトをキャストする必要があることがよくあります。コンパイル時間タイプチェックによって提供される信頼性と保守性が向上したため、これを実行するために暗黙的な変換を使用することを常に好みました。私がこれを行うことを知っている唯一の方法は、2行のコードを含み、スコープに別の変数を導入します。以下は例です:
public interface IMyType
{
string SayHello();
}
public class MyType : IMyType
{
string IMyType.SayHello() { return "Hello!"; }
}
class Program
{
static void Main(string[] args)
{
var item = new MyType();
// Option 1 - Implicit cast. Compile time checked but takes two lines.
IMyType item2 = item;
System.Console.WriteLine(item2.SayHello());
// Option 2 - One line but risks an InvalidCastException at runtime if MyType changes.
System.Console.WriteLine(((IMyType)item).SayHello());
// Option 3 - One line but risks a NullReferenceException at runtime if MyType changes.
System.Console.WriteLine((item as IMyType).SayHello());
}
}
コンパイラだから 知っている それ MyType
道具 IMyType
私は、その後の宣言に変更された後、暗黙のキャストは明示的なキャストよりも優れていると思います MyType
anの代わりにコンパイルエラーが発生します InvalidCastException
実行時に。ただし、明示的なキャスト構文のシンプルさをやや好み、他の人のコードで使用されることがよくあります。
私の質問は3つあります:
- 上記のオプションのどれが好きですか(そしてその理由)?
- これを行うためのより良い方法はありますか?
- 暗黙のキャストが可能な場合、明示的なキャストを実行することに関するベストプラクティスは何ですか?
解決
これがコンパイル時間チェックされた1つのライナーです:
public static class Converter
{
public static T ReturnAs<T>(T item)
{
return item;
}
}
class Program
{
static void Main(string[] args)
{
var item = new MyType();
// Option 1 - Implicit cast. Compile time checked but takes two lines.
IMyType item2 = item;
System.Console.WriteLine(item2.SayHello());
// Option 2 - One line but risks an InvalidCastException at runtime if MyType changes.
System.Console.WriteLine(((IMyType)item).SayHello());
// Option 3 - One line but risks a NullReferenceException at runtime if MyType changes.
System.Console.WriteLine((item as IMyType).SayHello());
// Option 4 - compile time one liner
Converter.ReturnAs<IMyType>(item).SayHello();
}
}
他のヒント
3つの質問すべてに対する答えとして:一般的なルールとして暗黙のキャストに依存しています。実装ではなく、インターフェイスに対してプログラミングしています。
最後の点に関しては、実装(特定の派生クラス)に対するプログラミングに本当に頼らなければならない場合は、それを試みる前にオブジェクトを型にキャストできることを確認してください。このようなもの:
var IMyType item3 = item as MyConcreteType;
if(item3 != null) {
item3.SayHello();
}
オブジェクトがインターフェイスのインスタンスであるかどうかわからない場合は、AS/nullチェックを実行します。通常、メソッド/関数呼び出しからインターフェイスを返します。この場合、キャストなしで変数に保存するだけです(nullチェックが必要になる場合があります)。
私は通常それが好きです:
class Program
{
static void Main(string[] args)
{
var item = new MyType();
if( item is IMyType ){
Console.WriteLine( (item as IMyType).SayHello() );
}
else { /* Do something here... */ }
}
}