15

最近、いくつかのクラスの名前変更を含むいくつかのコードをリファクタリングした後、私のコードのいくつかは驚くべき方法で壊れました。原因は「is」演算子テストの失敗でした。コンパイラのエラーや警告ではないことに非常に驚いていました。

この完全なプログラムは状況を示しています。

static class ExtensionMethods {}

class Program {

    static void Main() {
        Test("Test");
    }

    public static bool Test(object obj)
    {
        return obj is ExtensionMethods;
    }
}

ExtensionMethodsが静的クラスであることを考えると、「objisExtensionMethods」が何らかの警告を発することを期待していました。

たとえば、テスト対象のオブジェクトが指定されたタイプになることができない場合、コンパイラは「is」演算子に対して警告を発行します((string)obj) is System.Uri

これが実際に意味のあるテストになるシナリオを忘れていますか?

4

5 に答える 5

11

コンパイラのエラーや警告ではなかったので、とても驚きました。

あるべきだった。それは見落としでした。

静的クラスに関連するようなバグがいくつかありました。正しく思い出せば、Vladimir Reshetnikovが、型推論で型パラメーターの境界として静的型を推論できるという奇妙なシナリオさえありました。

どうやら私が前に見たこれは、決して修正されませんでした。見落としをお詫びします。

これが実際に意味のあるテストになるシナリオを忘れていますか?

いいえ。

于 2013-02-15T01:58:19.587 に答える
4

C#3.0仕様のセクション10.1.1.3から:

静的クラスにはクラスベース仕様(§10.1.4)を含めることはできず、基本クラスまたは実装されたインターフェイスのリストを明示的に指定することはできません。静的クラスは、オブジェクト型から暗黙的に継承します。

isしたがって、コンパイラは、が常にfalseを返すことを知らないため、警告を出さないようです。(静的クラスは「is」であるobjectため、コンパイラはobjectコンパイル時に「is」または「is」が静的クラスではないことを認識しません。)現実的には、それはおそらく知っているか、少なくとも見つけることができますが、明らかにそのケースを専門にしてチェックしません。

于 2013-02-15T00:19:52.600 に答える
1

私はこれにひびを入れました、そしてこれをMSDNリファレンスで見つけることができませんが、それはオペラトロアがチェックできるようにタイプをインスタンス化することに依存しているように見えます。静的クラスはインスタンス化できないため(静的クラスはコンパイル時にプログラムスタック上に作成されたオブジェクトであるため)...

たとえば、以下を実行すると、次のエラーが発生します:「静的型の変数を宣言できません」

ExtensionMethods ex;

また、以下を実行すると、次のエラーが発生します:「静的クラスのインスタンスを作成できません」

ExtensionMethods ex2 = new ExtensionMethods();

この問題を実証するために、is演算子を示す完全なプログラムを次に示します。

static class ExtensionMethods { }

// notice non-static
class AnotherNonStaticExtensionMethod { }

class Program
{
    static void Main(string[] args)
    {
        Debug.WriteLine(Test(new AnotherNonStaticExtensionMethod()).ToString());
        Debug.WriteLine(Test("Test").ToString());
        Debug.WriteLine(Test(4).ToString());
    }

    public static bool Test(object obj)
    {
        if (obj is ExtensionMethods)
        {
            return true;
        }
        else if (obj is AnotherNonStaticExtensionMethod)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

次の出力があります。

True
False
False

isオブジェクトは、最初のステートメントでインスタンス化可能なクラスをチェックできます。したがって、is演算子はそれに依存していると私は信じています。誰かがこれを確認できるといいのですが?

NominSimの礼儀::

C#3.0仕様のセクション10.1.1.3から:

静的クラスにはクラスベース仕様(§10.1.4)を含めることはできず、基本クラスまたは実装されたインターフェイスのリストを明示的に指定することはできません。静的クラスは、オブジェクト型から暗黙的に継承します。

于 2013-02-15T00:19:43.783 に答える
1

2013年のEricLippertの回答によると、これはVisual C#5.0コンパイラ(および以前のバージョンも)のバグでした。asたとえば、オペレーターにも問題がありましたobject bad = obj as ExtensionMethods;

C#6.0(2015以降)以降では、コンパイル時エラーが発生します(単なる警告ではありません)。

エラーCS7023:「is」または「as」演算子の2番目のオペランドは静的タイプ「Xxxx」ではない可能性があります

ただし、これは機能Strictを指定した場合にのみ当てはまります。その方法の詳細については、別のスレッドを参照してください

于 2017-05-04T14:18:39.520 に答える
0

C#言語仕様によると:

is演算子は、オブジェクトの実行時型が特定の型と互換性があるかどうかを動的にチェックするために使用されます。演算Eの結果はTです。ここで、Eは式、Tは型であり、参照変換、ボックス化変換、またはボックス化解除変換によってEがタイプTに正常に変換できるかどうかを示すブール値です。

静的クラスにはクラスベース仕様(§10.1.4)を含めることはできず、基本クラスまたは実装されたインターフェイスのリストを明示的に指定することはできません。静的クラスは、オブジェクト型から暗黙的に継承します。

は暗黙的に継承するためSystem.Object、コンパイラが警告を発行していないことは理にかなっています。

検証:

var staticBaseType = typeof(B).BaseType;

System.Object基本タイプとしてを取得します。

于 2013-02-15T00:46:44.917 に答える