6

一連のプロパティを含むクラスがあります。その型のオブジェクトで ToString() を呼び出すのは、プログラマーの間違いです。このコード例を見てください:

using System;

public class Foo
{
    public int ID = 123;
    public string Name = "SomeName";

    private string ToString() { return null; }
}

public class MyClass
{
    public static void Main()
    {
        Foo myObj = new Foo();
        WL("I want this to be a compiler error: {0}", myObj.ToString());
        RL();
    }

    #region Helper methods

    private static void WL(object text, params object[] args)
    {
        Console.WriteLine(text.ToString(), args);   
    }

    private static void RL()
    {
        Console.ReadLine(); 
    }

    #endregion
}

ほとんどの人が ID を文字列として書き出す必要がある場合は、ID を返すように ToString を実装する必要があると考えることができます。ただし、プログラマーは「偶然」にコードを動作させるため、これは悪い習慣だと思います。私のクラスを使用するプログラマーは、必要なものを指定する必要があります。

代わりに、誰かが myObj.ToString() を呼び出して、コンパイル時エラーとして表示されるようにしたいのです。プライベートな ToString() 関数を作成することでそれができると思ったのですが、うまくいきません。

これを取り上げた理由は、ID ではなく完全修飾クラス名を含むクエリ文字列になってしまったためです。

質問は次のとおりです。クラスのオブジェクトで ToString() 関数を呼び出すとコンパイラ エラーが発生するように、ToString() 関数を「非表示」にする方法はありますか?

4

7 に答える 7

45

このデザインがどれほど悪いアイデアであるかを十分に強調することはできません.

ToString().Net のオブジェクト コントラクトの一部です。実装したくない場合は、オーバーライドせずに、型情報を返すようにしてください。それはどのような害をもたらす可能性がありますか?

私はそれほど否定的であるつもりはありませんが、誰かがToString().

いくつかの追加ポイント:

  1. ToString()このクラスを使用するプログラマーが、ID が返されると想定するのはなぜですか? エコシステム内の他のクラスはこれを行っていますか? ToString()意味のあるデータを返す必要があると主張することができます。ToString()しかし、呼び出し の結果に対してプログラミングを行うべきではありません。ToString()クラス、ピリオドの文字列表現用です。これは、プログラマーまたは部門間の教育またはコミュニケーションの問題のように思えます。

  2. ToString()コンパイル時に方法を理解できるか、実行時に例外をスローするかによって、何らかの方法で機能を損なうと、波紋が発生します。私はこれが行われたのを見たことがなく、私が使用しているクラスがこの動作を示すとは思っていません。ほとんどのプログラマーは同じ期待を持っていると思います。あなたのクラスを使用する将来のプログラマーはこれを期待しますか? 今後、どのようなバグやメンテナンスの悪夢を引き起こしますか?

  3. これは、依存する IDE またはデバッガーにどのような影響を与えますToString()か?

  4. 特定の型にバインドせず、実行時にリフレクションを使用して値を引き出すデータバインディング テクノロジを使用する場合、これはどのような影響を与えるでしょうか? ToString()使用するメンバーが指定されていない場合、ほとんどのデータバインディングはオブジェクトの呼び出しにフォールバックします。

于 2008-10-20T15:47:10.250 に答える
20

Obsolete 属性を使用すると、これを行うことができます。

[Obsolete("Use the XYZ properties instead of .ToString() on Foobar", true)]

最後のブール値は、コンパイラがこのメンバーの使用をエラーと見なすかどうかを指定します。

于 2008-10-20T15:42:35.470 に答える
7

いくつかの理由から、これに Obsolete プロパティを使用することに完全に同意しません。

まず、オーバーライドして Obsolete プロパティでタグ付けした ToString() メソッドに対する警告が表示されます。

    [Obsolete("dont' use", true)]
    public override string ToString()
    {
        throw new Exception("don't use");
    }

次の警告が生成されます: 警告 1 古いメンバー 'ClassLibrary1.Foo.ToString()' は、非古いメンバー 'object.ToString()' をオーバーライドします

そのため、コードに永続的な警告が表示されます。これに加えて、問題を正確に解決するわけではありません。フレームワーク内の何かが暗黙的に ToString() を呼び出すとどうなりますか? 次のコードの結果は、ToString() の本体のコードがまだ呼び出されていることです。

        Foo myObj = new Foo();

        Console.WriteLine(myObj);

これで、コードに警告が表示されましたが、実際には、開発者が同じことを何度もやり直すことを妨げていません。ここでの正しい動きは、.net オブジェクト コントラクトをいじろうとするのではなく、実行時に適切な例外をスローする方法を見つけようとすることだと思います。

コンパイル時に問題をキャッチするための提案: この問題の解決策を以前に提案していなかったことに気付きました。あなたのIDがどの形式であるかはよくわからないので、それがintであると推測しているだけですが、クエリ文字列でURLを作成しているものを保護し、IDをintとして渡してみませんか。こうすることで、開発者はコンパイル エラーなしで無意味な文字列を誤って渡すことができなくなります。たとえば、次のようにします。

public string CreateItemUrl(int itemId)
{
   return string.Format("someurl.aspx?id={0}", itemId);
}

今、これを呼び出します:

CreateItemUrl(myObj.Id);

次のものよりもはるかに強く型付けされ、エラーが発生しにくくなります。

string theUrl = string.Format("someurl.aspx?id={0}", myObj);
于 2008-10-20T16:11:46.240 に答える
7

ハイブリッドなアプローチをとります。(ねえ、他の答えを組み合わせるのはSOではありませんか?:))

まず、void を返す新しい ToString を作成します。戻り値がないということは、それを使用して誤って素敵なコードを取得できないことを意味します。

public new void ToString() { }

次に、Obsolete 属性を追加して、人々がそれを呼び出すと、ToString が悪いという警告が表示されるようにします。

このように ToString をオーバーライドする必要はありません。単に役に立たないもので非表示にします。戻り値がないという事実は、すべてのコードを破壊するため、廃止されたメッセージに加えてコンパイラ エラーが発生します。

私があなたの質問を直接理解していれば、オブジェクトにキャストする人々はあなたの関心事ではありません。人々が ToString を呼び出して型情報を取得するのを防ぎたいのではなく、ToString が有用な結果を提供すると誤って考えてしまうのを防ぎたいのです。

編集: 例外をスローしたり、ToString をオーバーライドしたりしないでください。オブジェクトがオブジェクトとして扱われると、「悪いこと」が発生します。「new」を使用するだけで、他のフレームワークを台無しにすることなく、求めていた利点が得られます。

于 2008-10-20T20:37:13.833 に答える
1

ToString をオーバーライドして string.Empty を返すと、クエリ文字列に何も追加されません。デフォルトでは、ToString をオーバーライドしない場合、名前空間やクラス名のようなものを提供する this.GetType() を返すオブジェクトのバージョンを取得します。

ToString を呼び出すことはかなり合理的なことのように思えますが、それを行う人にコンパイラ エラーを発生させたくありません。

于 2008-10-20T15:52:09.320 に答える
1

public ToString() 関数で override キーワードを使用して、System.Object ToString() メソッドをオーバーライドします。

于 2008-10-20T15:43:25.377 に答える
0

あなたのデザイン/意見が変更されることを考慮してください:)

まず、Foo.ToString の定義は Object.ToString() のオーバーライドを定義するのではなく、新しいオーバーライドを定義し、セマンティクスの誤解を防ぐために "new" キーワードをプレフィックスとして付ける必要があります。または明示的に「オーバーライド」を宣言します。私見、コンパイラは対応する警告を発行します。

Foo.ToString の呼び出しを禁止する方法を見つけたとしても、「this」の型が Foo または子孫であることがわかっている場合にのみ、コンパイル時に禁止されますが、 ((object) foo).ToString() ToString は Object インターフェイスのメソッドであるため、正しい回避策になります。

また、ToString の呼び出しを防止することは望ましくありません。これは、Debugger がそれを使用して値を提示するためです。SY、ジェイク

于 2008-10-20T16:20:04.460 に答える