2

を避ける必要がありNullReferenceExceptionます。現在、次のものがあります。

ISomeInterface interface = this.GetISomeInterfaceInstance();
(interface as ClassImplmentsISomeInterface).Method();

これは問題なく動作しますが、リスクがありますNullReferenceException。1つの解決策は次のとおりです。

ISomeInterface interface = this.GetISomeInterfaceInstance();
ClassImplmentsISomeInterface instance = interface as ClassImplmentsISomeInterface;
if (instance != null)
    instance.Method();

しかし、これは単純なチェックのために多くの余分なコードを生成します (resharper によると、数百の可能な NRE があります)。2 番目の解決方法は次のとおりです。

ISomeInterface interface = this.GetISomeInterfaceInstance();
if (interface is ClassImplmentsISomeInterface)
    (interface as ClassImplmentsISomeInterface).Method();

しかし、is実際asにはバックグラウンドで使用しているため、キャストを 2 回行うことは避けたいと考えています。これは問題ですか?たとえば、C# コンパイラは、このパフォーマンスの問題を最適化するのに十分賢いでしょうか?

ここで見逃している他のテクニックはありますか?または、上記の方法のいずれかが望ましいですか?

4

7 に答える 7

4

あなたのコードを短くする素晴らしい方法を考えることができます:

public static void InvokeIfIsT<T>(object o, Action<T> action)
{
    if (o is T)
       action((T)o);
}

そのように使用します:

ISomeInterface interface = this.GetISomeInterfaceInstance();
InvokeIfIsT<ClassImplmentsISomeInterface>(interface, i => i.Method());
于 2012-08-16T09:35:43.953 に答える
2

結果がそうでない場合はブール値をis使用asして返すという点で正しいです(逆も同様です)truenull

ただし、resharper ルールは、従うべきルールではなく、ヒントまたはガイドラインとして使用することをお勧めします (実際にはオフにします)。

あなたのコードを検討してください

ISomeInterface interface = this.GetISomeInterfaceInstance();
(interface as ClassImplmentsISomeInterface).Method();
 //error thrown above as null reference

今、あなたは先に進み、それをリファクタリングします

ISomeInterface interface = this.GetISomeInterfaceInstance();
if (interface is ClassImplmentsISomeInterface)
{
    (interface as ClassImplmentsISomeInterface).Method();
}
else
{
    //else?? else what? how do you recover?
}

例外がただの例外である場合、例外に問題はありません。

「elseシナリオの処理は例外よりもコストがかからない」と言うかもしれませんが、これは回復できる場合にのみ当てはまります。たとえば、次のようなものを書くことができた場合

ISomeInterface interface = this.GetISomeInterfaceInstance();

try
{
    (interface as ClassImplmentsISomeInterface).Method();
}
catch (NullReferenceException)
{
    interface = this.GetIOtherInterface().Method();
}

実際に何か役に立つことをしているので、ヌルチェックにリファクタリングする価値があります。メソッドが正常に回復できない場合は、どこかでメソッドが呼び出し元に例外をスローして、「何か問題が発生しました」と言う必要があります。

于 2012-08-16T09:42:41.423 に答える
1

!= null何かがnullであると思われる場合、私は個人的にテストを使用します。しかし、Interface オブジェクトを具体的なオブジェクトにキャストしていることが原因である場合は、一歩下がって設計を再評価する必要があると思います。Interface オブジェクトを使用するために具体的なオブジェクトにキャストする必要がある場合、失敗したと思います。

ファクトリを使用してインターフェイスを実装するオブジェクトを取得しますが、それを使用するために具体的なオブジェクトにキャストする必要があるのはタブーです。インターフェイスがメソッドを指定する場合、インターフェイスを実装するオブジェクトの種類を気にする必要はありません。メソッドの機能に関心がある場合は、別のインターフェイスを作成し、具象クラスにそれを実装させる必要があります。

クラスは好きなだけインターフェイスを実装できることに注意してください。

于 2012-08-16T09:39:08.063 に答える
0

私は通常一緒に行きます

ISomeInterface variable = this.GetISomeInterfaceInstance();
var myInterface = variable as ClassImplmentsISomeInterface;

if(myInterface != null)
 myInterface.Method();
于 2012-08-16T09:18:01.423 に答える
0

投機的にキャストしたい場合は、最初のオプション (asおよびnullチェック) をお勧めします。ただし、キャストが不要になるようにコードをリファクタリングすることも検討する必要があります。

于 2012-08-16T09:18:08.510 に答える
0

場合によっては、パターン NullObject で対処できます。キャスト メカニズムをカプセル化し、NullObject を返すことができます。ただし、シナリオに適合する場合にのみ使用してください

Null Object パターン wiki ページ

于 2012-08-16T09:20:52.937 に答える
0

プロキシ パターンを使用して、次のNullObjectようにシミュレートできます。

class ClassImplmentsISomeInterfaceProxy:ClassImplmentsISomeInterface
{
      ClassImplmentsISomeInterface target;
      ClassImplmentsISomeInterfaceProxy(ISomeInterface actual)
      {
          target=actual as ClassImplmentsISomeInterface;
      }
      //method implementations, with check for null
}

ただし、そのような設計が本当に必要であることを確認してください。通常、型チェックを行わないということは、リファクタリングする必要があることを意味します。

于 2012-08-16T09:23:25.010 に答える