2

さて、私がそのような構造Aを持っているとしましょう:

Struct A{
    private String _SomeText;
    private int _SomeValue;

    public A(String someText, int SomeValue) { /*.. set the initial values..*/ }

    public String SomeText{ get { return _SomeText; } }
    public int SomeValue{ get { return _SomeValue; } }
}

今、私ができるようにしたいのは、次のように、クラスABCのメソッドの結果としてその構造体Aを返すことです。

Class ABC{
    public A getStructA(){
        //creation of Struct A
        return a;
    }
}

ライブラリ(StructAとClassABCなどが含まれる)を使用しているプログラマーがStructAのインスタンスを作成できるようにし
たくありません。作成する唯一の方法はリターンとしてです。 getStructA()メソッドから。次に、適切なゲッターを介して値にアクセスできます。

それで、そのような制限を設定する方法はありますか?では、Structureを特定のクラスの外部でインスタンス化することはできませんか?C#、.Net4.0を使用します。

ご協力いただきありがとうございます。

---編集:----
なぜ私がこれを達成しようとしているのかについての詳細を追加するには:

  • 私のクラスABCには、人が照会できる「ステータス」があります。このステータスには、2つの文字列値と、整数の長いリストがあります。
  • プログラマーが「Status」のオブジェクト/インスタンスを作成する必要はありません。ステータスは、クラスの「getStatus()」関数によってのみ返されます。
  • これらの3つのフィールドを異なるメソッドに分割したくないのは、それらを取得するために、3つのフィールドすべてで同様の構造体を返すWindows API(p / invoke)を呼び出しているためです。
  • 実際に3つのメソッドに分割し、構造体を使用しない場合は、これら3つのメソッドのいずれかが呼び出されるたびに、結果をキャッシュするか、WindowsAPIからメソッドを呼び出す必要があります...

したがって、パブリック構造体を作成し、プログラマーが必要に応じてインスタンス化することもできます。これは、パラメーターとして受け入れることができるメソッドがないため、役に立たないでしょう。または、この構造体(または、作業が簡単になる場合はクラスに変更)がメソッドからの戻りとしてのみ取得できるようにライブラリを構築することもできます。

4

3 に答える 3

10

「制限された」タイプが構造体である場合、いいえ、それを行う方法はありません。構造体は少なくともファクトリ メソッドと同じくらい公開されている必要があり、構造体が公開されている場合は、既定のコンストラクターで構築できます。ただし、これを行うことができます:

public struct A
{
    private string s;
    private int i;
    internal bool valid;
    internal A(string s, int i)
    {
        this.s = s;
        this.i = i;
        this.valid = true;
    } 
    ...

これで、ライブラリ コードに「有効な」フラグをチェックさせることができます。A のインスタンスは、(1) 内部コンストラクターを呼び出すことができるライブラリーの内部メソッドによって、または (2) デフォルトのコンストラクターによってのみ作成できます。有効なフラグでそれらを区別できます。

多くの人がインターフェイスの使用を提案していますが、それは少し無意味です。構造体を使用することの要点は、値の型のセマンティクスを取得してから、それをインターフェイスにボックス化することです。そもそもそれをクラスにすることもできます。それがクラスになる場合、ファクトリ メソッドを作成することは確かに可能です。クラスのすべてのctorを内部にするだけです。

そしてもちろん、完全に信頼できるユーザーによる攻撃に耐性のあるコードを実装するために、このツールを使用すべきではないことは言うまでもありません。このシステムは、善良なユーザー悪質なコードから保護するためのものであり、善良なコードを悪質なユ​​ーザーから保護するためのものではないことを忘れないでください。完全に信頼されたユーザー コードが、リフレクションを介してライブラリ内で必要なプライベート メソッドを呼び出したり、安全でないコードで構造体内のビットを変更したりするのを阻止するものは何もありません。

于 2013-02-07T16:49:07.807 に答える
0

いったい何を気にしているのですか?構造とは、基本的にフィールドをガムテープでくっつけたものです。構造体の代入は、ある構造体インスタンスから別の構造体インスタンスにすべてのフィールドをコピーするため、問題の構造体型の制御外であるため、特にマルチスレッド コードでは (構造体が正確に1、2、または 4 バイトのコードでは、2 つの異なるインスタンスからコピーされたデータの混合を含むインスタンスを作成するコードは非常に簡単に作成でき、構造体でそれを防ぐ方法はありません)。

メソッドが、型が内部的に生成したもの以外の型のインスタンスを受け入れないようにする場合は、internalまたはprivateコンストラクターのみを持つクラスを使用する必要があります。そうすれば、自分で作成したインスタンスを確実に取得できます。

編集 改訂に基づいて、要求されたタイプの制限が必要または特に役立つとは思いません。一連の値をまとめて、呼び出し元が保持する変数のまとまったグループに格納することが基本的に望まれているように思えます。構造体を単純に宣言する場合:

public struct QueryResult {
  public ExecutionDuration as Timespan;
  public CompletionTime as DateTime;
  public ReturnedMessage as String;
}

次に、宣言:

QueryResult foo;

foo.ExecutionDurationfoo.CompletionTime、という名前の 3 つの変数を効果的に作成しますfoo.ReturnedMessage。ステートメント:

foo = queryPerformer.performQuery(...);

関数の結果に従って、これら 3 つの変数の値を設定します。

{
  var temp = queryPerformer.performQuery(...);
  foo.ExecutionDuration = temp.ExecutionDuration
  foo.CompletionTime = temp.CompletionTime;
  foo.ReturnedMessage = temp.ReturnedMessage;
}

ユーザー コードがこれら 3 つの変数を使用して実行することを妨げるものは何もありません。なんらかの理由でユーザーコードが決定した場合はfoo.ReturnedMessage = "George";foo.ReturnedMessageと等しくなりGeorgeます。状況は、コードが次のように言った場合とまったく変わりません。

int functionResult = doSomething();

そして後で言っfunctionResult = 43;た。の動作はfunctionResult、他の変数と同様に、最後に書き込まれたものを保持することです。最後に書き込まれたものが への最後の呼び出しの結果である場合、doSomething()それが保持されます。最後に書かれたものが何か他のものだった場合、それは何か他のものを保持します。

クラスフィールドや構造体プロパティとは異なり、構造体フィールドは、それに書き込むか、構造体代入ステートメントを使用して 1 つの構造体インスタンスのすべてのフィールドを別の対応するフィールドの値とともに書き込むことによってのみ変更できることに注意してください。 . 消費者の観点からは、読み取り専用の構造体プロパティにはそのような保証はありません。構造体はたまたまそのように動作するプロパティを実装する場合がありますが、プロパティのコードを検査しないと、構造体が返す値が変更可能なオブジェクトの影響を受けているかどうかを知る方法はありません。

于 2013-02-07T17:20:45.173 に答える
0

パブリック インターフェイスを作成し、それを呼び出すクラスに対してクラスをプライベートにします。

public ISpecialReturnType
{
    String SomeText{ get; }
    int SomeValue{ get; }
}

class ABC{
    public ISpecialReturnType getStructA(){
        A a = //Get a value for a;
        return a;
    }

    private struct A : ISpecialReturnType
    {
        private String _SomeText;
        private int _SomeValue;

        public A(String someText, int SomeValue) { /*.. set the initial values..*/ }

        public String SomeText{ get { return _SomeText; } }
        public int SomeValue{ get { return _SomeValue; } }
    }
}
于 2013-02-07T16:21:51.780 に答える