3


0

C#で静的キャストを行う方法は?

次のようないくつかのタイプを考えます:

interface I {}
class C : I {}

静的型キャストを実行するにはどうすればよいですか? つまり、コンパイル時にチェックされるようにその型を変更するにはどうすればよいですか?

C ++では、 `static_cast(c)`を実行できます。 C#でできる最善の方法は、代替タイプの一時変数を作成し、割り当てを試みることです。

var c = new C();
I i = c;  // statically checked

しかし、これは流fluentなプログラミングを妨げます。 型チェックを行うためだけに、新しい変数を作成する必要があります。 だから私はこのようなものに落ち着いた:

class C : I
{
    public I I { get { return this; } }
}

これで、 `c.I`を呼び出すだけでCを静的に変換できます。

C#でこれを行うより良い方法はありますか?

(なぜ私がこれをしたいのか疑問に思っている場合は、明示的なインターフェイス実装を使用しているため、別のメンバー関数内からそれらのいずれかを呼び出すには、最初にインターフェイス型へのキャストが必要です。そうでない場合、コンパイラはメソッドを見つけることができません)

更新

私が思いついた別のオプションはオブジェクト拡張です:

public static class ObjectExtensions
{
    [DebuggerStepThrough]
    public static T StaticTo(this T o)
    {
        return o;
    }
}

そのため、 `((I)c).Doit()`は `c.StaticTo()。Doit()`にもなります。 うーん…​おそらくまだ単純なキャストに固執します。 とにかく、私はこの他のオプションを投稿すると思いました。

4 Answer


5


それを単に投げなさい:

(I)c

編集例:

var c = new C();

((I)c).MethodOnI();


2


var c = new C();
I i = c;  // statically checked

等しい

I i = new C();


2


UPDATEで言及したトリックを使用する拡張メソッドを作成します。

public static class ObjectExtensions
{
    public static T StaticCast(this T o) => o;
}

使用するには:

things.StaticCast().GetEnumerator();

「もの」が「IEnumerable」などの場合、これはコンパイルされます。 「もの」が「オブジェクト」の場合、失敗します。

// Compiles (because IEnumerable is known at compiletime
// to be IEnumerable too).
"adsf".StaticCast().GetEnumerator();

// error CS1929: 'object' does not contain a definition for 'StaticCast'
// and the best extension method overload
// 'ObjectExtensions.StaticCast(IEnumerable)'
// requires a receiver of type 'IEnumerable'
new object().StaticCast().GetEnumerator();

静的キャストを使用する理由

リファクタリング中の一般的なプラクティスの1つは、先に進んで変更を加え、変更によってリグレッションが発生していないことを確認することです。 さまざまな方法でさまざまな段階で回帰を検出できます。 たとえば、一部のタイプのリファクタリングでは、APIの変更/破損が発生し、コードベースの他の部分のリファクタリングが必要になる場合があります。

コードの一部がコンパイル時にインターフェイス( IInterfaceA)を実装する必要がある型(` ClassA`)を受け取ることを期待し、そのコードがインターフェイスメンバーに直接アクセスする場合、インターフェイスにキャストする必要があります。たとえば、明示的に実装されたインターフェイスメンバーにアクセスするために入力します。 リファクタリング後に、* ClassA`が IIterfaceA` *を実装しなくなった場合、インターフェイスへのキャスト方法に応じてさまざまなタイプのエラーが発生します。

  1. Cスタイルのキャスト: `((IInterfaceA)MethodReturningClassA())。Act();`は 突然ランタイムキャストになり、ランタイムエラーをスローします。

  2. 明示的に型指定された変数への割り当て: `IInterfaceA a = MethodReturningClassA(); a.Act(); `はコンパイル時エラーを発生させます。

  3. `static_cast`のような拡張メソッドを使用する: `MethodReturningClassA()。StaticCast()。Act();`はコンパイル時エラーを発生させます。

キャストがダウンキャストであり、コンパイル時に検証可能であると予想した場合は、コンパイル時の検証を強制するキャストメソッドを使用する必要があります。 これにより、コードの元の開発者が型保証コードを作成する意図が明確になります。 そして、タイプセーフなコードを書くことは、コンパイル時により検証可能であるという利点があります。 他の開発者、自分、およびコンパイラの両方に型安全性をオプトインする意図を明確にするために少し作業を行うことで、コードの検証でコンパイラの助けを魔法のように取得し、リファクタリングの影響をより早く(コンパイル時に)キャッチできます(コードが完全にテストカバレッジされなかった場合のランタイムクラッシュなど)。


1


オブジェクトが特定の型を実装しているかどうかを確認する方法を本当に探している場合は、「as」を使用する必要があります。

I i = whatever as i;
if (i == null) // It wasn't

それ以外の場合は、キャストするだけです。 (.NETには、C ++のように実際に複数のタイプのキャストはありません-ほとんどの人が必要とするより深くならない限り、しかし、それはWeakReferenceなどについての詳細です。)

I i = (I)c;

「I」を実装するものを「I」に変える便利な方法を探しているだけなら、拡張メソッドなどを使用できます。

public static I ToI(this I @this)
{
    return @this;
}