10

次の設定をしたいと思います。

class Descriptor
{
    public string Name { get; private set; }
    public IList<Parameter> Parameters { get; private set; } // Set to ReadOnlyCollection

    private Descrtiptor() { }
    public Descriptor GetByName(string Name) { // Magic here, caching, loading, parsing, etc. }
}

class Parameter
{
    public string Name { get; private set; }
    public string Valuie { get; private set; }
}

XML ファイルからロードされると、構造全体が読み取り専用になります。Descriptor クラスだけが Parameter をインスタンス化できるようにしたいと思います。

これを行う 1 つの方法は、IParameterインターフェイスを作成してからParameter、Descriptor クラスでクラスをプライベートにすることですが、実際の使用では、パラメーターにはいくつかのプロパティがあり、それらを 2 回再定義することは避けたいと思います。

これはどういうわけか可能ですか?

4

6 に答える 6

21

特定のインターフェイスを実装するネストされたプライベート クラスにします。次に、外部クラスのみがそれをインスタンス化できますが、誰でも (インターフェイスを介して) 使用できます。例:

interface IParameter
{ 
    string Name { get; } 
    string Value { get; }
}

class Descriptor
{
    public string Name { get; private set; }
    public IList<IParameter> Parameters { get; private set; }

    private Descriptor() { }
    public Descriptor GetByName(string Name) { ... }

    class Parameter : IParameter
    {
        public string Name { get; private set; }
        public string Value { get; private set; }
    }
}

本当にインターフェイスを避ける必要がある場合は、すべてのプロパティを持ちながら保護されたコンストラクターを宣言する public 抽象クラスを作成できます。次に、外部クラスによってのみ作成され、そのインスタンスを基本型として返すパブリック抽象から継承するプライベート ネスト クラスを作成できます。例:

public abstract AbstractParameter
{ 
    public string Name { get; protected set; } 
    public string Value { get; protected set; }
}

class Descriptor
{
    public string Name { get; private set; }
    public IList<AbstractParameter> Parameters { get; private set; }

    private Descriptor() { }
    public Descriptor GetByName(string Name) { ... }

    private class NestedParameter : AbstractParameter
    {
        public NestedParameter() { /* whatever goes here */ }
    }
}
于 2009-12-18T16:06:27.513 に答える
4

LBushkin は正しい考えを持っています。すべてのプロパティを再入力する必要がないようにしたい場合は、クラスの名前を右クリックして [リファクタリング] > [インターフェイスの抽出] を選択するだけで、これらすべてのプロパティを含むインターフェイスが得られます。(これは VS 2008 で動作します。以前のバージョンについては知りません。)

C# は一般に、冗長なコードを回避する代わりに、VS がコードをより速く作成するのに役立つというアプローチをとっています。

于 2009-12-18T16:13:50.590 に答える
1

StrongNameIdentityPermission属性SecurityAction.LinkDemandオプションを使用して、インスタンス化(パラメーター)から「保護」するクラスをマークします。

[StrongNameIdentityPermission(SecurityAction.LinkDemand, PublicKey="...")]
class Parameter
{
    ...
}

適切な公開鍵を提供する必要があります。クラスのリンク時間(実際にはJIT時間)チェックを要求しているためParameter、これは、公開鍵と一致する秘密鍵を使用する厳密な名前で署名されたアセンブリからのみ使用できることを意味します。上記の属性コンストラクターで指定します。もちろん、Descriptorクラスを別のアセンブリに配置し、それに応じて強い名前を付ける必要があります。

私はこの手法をいくつかのアプリケーションで使用しましたが、非常にうまく機能しました。

お役に立てれば。

于 2009-12-18T17:43:55.807 に答える
1

Internal とマークされたコンストラクターを使用できます。

こうすることで、アセンブリ内のクラスに対してパブリックになり、アセンブリ外のクラスに対してプライベートになります。

于 2009-12-18T16:06:24.503 に答える
0

別の方法があります。呼び出しタイプのコール スタックを確認します。

于 2009-12-18T16:21:11.573 に答える
-1

Descriptor クラスだけで Parameter をインスタンス化する場合は、Descriptor クラスを Parameter のネストされたクラスにすることができます。(その逆ではありません) コンテナまたは親クラスがネストされたクラスであるため、これは直感に反します。

public class Parameter  
{  
  private Parameter() { }
  public string Name { get; private set; }
  public string Value { get; private set; }
  public static Parameter.Descriptor GetDescriptorByName(string Name)
  {
    return Parameter.Descriptor.GetByName(Name);
  }
  public class Descriptor
  { // Only class with access to private Parameter constructor
    private Descriptor() { // Initialize Parameters }
    public IList<Parameter> Parameters { get; private set; } // Set to ReadOnlyCollection
    public string Name { get; private set; }
    public static Descriptor GetByName(string Name) { // Magic here, caching, loading, parsing, etc. }
  }  
}
于 2009-12-18T17:41:01.740 に答える