1

プロパティを含む実装の詳細を含む内部クラスがありますが、パブリックにアクセスすることはできません。このクラスを公開呼び出し元に渡して、それらを渡したり、保存したり、シリアル化したり、基本的に好きなことをしたりできるようにする必要があります。クラスは、2 つの異なる方法でパブリックにアクセスできます。これらの方法は、2 つのパブリック インターフェイスとして公開されます。ユーザーが 2 つのパブリック インターフェイス間でキャストできないようにしたいと考えています。ここに、私が話していることを示すコードをいくつか示します。

void Main()
{
    var container = new ContainsDetails(5);

    Console.WriteLine(container.LessDetail.TheDetails);
    var more = (ContainsDetails.IFooPlus)(container.LessDetail);
    more.TheDetails = 10;
    Console.WriteLine(container.LessDetail.TheDetails);
}

public class ContainsDetails {
    public interface IFooPlus {
        int TheDetails {
            get;
            set;
        }
    }

    public interface IFoo {
        int TheDetails {
            get;
        }
    }

    private readonly Detail _myDetail;

    public ContainsDetails(int x) {
        _myDetail = new Detail(x);
    }

    public IFoo LessDetail {
        get {
            return _myDetail;
        }
    }

    public IFooPlus MoreDetail {
        get {
            return _myDetail;
        }
    }

    public bool ProcessFoo(IFoo foo) {
        var theDeets = foo as Detail;
        if (theDeets != null) {
            return theDeets.TheDetails++%2 == 0;
        } else {
            throw new ArgumentException("foo argument must have originated from ContainsDetails.");
        }
    }

    private class Detail : IFooPlus, IFoo {
        private int _myX;

        private Detail() {}

        internal Detail(int x) {
            _myX = x;
        }

        public int TheDetails {
            get {return  _myX; }
            set { _myX = value; }
        }
    }
}

出力は次のとおりです。

5
10

上記の出力を次のようにしたいと思います。

5
System.InvalidCastException thrown.....

クラスContainsDetailsはデモンストレーションのために存在します。私の実際のコードでは、アセンブリが の役割を果たしContainsDetailsます。同様に、私の実際のコードDetailinternalクラスです。

IFooPlusここで、ユーザーはとの両方について知っていますIFoo。ユーザーはそれが存在することを知りませんDetailLessDetailユーザーは、 によって返されるオブジェクトが に変換可能であることも知りませんIFooPlus。私のコードは、Detailさまざまな時点で同じオブジェクトをユーザーに返し、他の内部オブジェクトの複雑な状態に応じて、IFooまたはそれに応じて返します。の方法にも注意してください。私のコードは、ユーザーからを受け取り、 として処理できる必要があります。 IFooPlusDetailProcessFooContainsDetailsIFooDetail

var more = (ContainsDetails.IFooPlus)(container.LessDetail)キャストが を生成するようにしたいと思いInvalidCastExceptionます。オブジェクトがそれらの操作に対して正しい状態にあるIFooPlusかどうかを判断するために、すべての操作に対して実行時チェックを行うのは非常にコストがかかります。代わりに、ユーザーが をとしてDetail扱えないようにしたいと思います。IFooIFooPlus

私が考えることができる唯一のオプションは、IFooメンバーのサブクラスを内部に埋め込みDetailDetailとサブクラスが相互に参照を保持するようにすることです。うん。

IFooこの種のキャストを防止するためのベスト プラクティスはありますか、それとも機能を のメンバー サブクラスで囲む必要がありDetailますか?

4

1 に答える 1

3

最も簡単な方法は、書き込み可能なラッパーへの参照を持つ読み取り専用ラッパーを用意することです。したがってLessDetail、常に同じラッパー参照MoreDetailを返しますが、「実際の」型への参照を返します。次に、それらの両方に内部インターフェイスを実装させて、必要なことを何でも実行できるようにすることができます。ラッパーは、おそらくそれらの呼び出しを基になるオブジェクトにプロキシします。

または、設計を再検討することもできます-型間でキャストできないか、コンパイル時にすべてをProcessFoo 受け入れるという点で、現時点では理想的ではありませんが、実際には特定の1つしか処理できません実装。これは私にとって継承の乱用のように感じます。IFoo

于 2012-07-09T06:25:32.677 に答える