2

同じ親から継承するオブジェクトで、親クラス (独自のアセンブリ内) で internal としてマークされているメソッドにアクセスしようとしています。

私がやろうとしていることを説明させてください...

基になる List を持つ IEnumberable を非 Service クラス (UI など) に返し、オプションで基になる IQueryable を持つ IEnumerable を他のサービスに返す Service クラスを作成したいと考えています。

以下に示すように、私が達成しようとしていることを示すためにいくつかのサンプルコードを書きました。この例は実際のものではないため、コメントするときはそのことを覚えておいてください。

すべてのサービスは、次のようなものから継承されます (関連するコードのみを示します)。

public class ServiceBase<T>
{
    protected readonly ObjectContext _context;
    protected string _setName = String.Empty;

    public ServiceBase(ObjectContext context)
    {
        _context = context;
    }

    public IEnumerable<T> GetAll()
    {
        return GetAll(false);
    }

    //These are not the correct access modifiers.. I want something
    //that is accessible to children classes AND between descendant classes
    internal protected IEnumerable<T> GetAll(bool returnQueryable)
    {
        var query = _context.CreateQuery<T>(GetSetName());
        if(returnQueryable)
        {
            return query;
        }
        else
        {
            return query.ToList();
        }
    }

    private string GetSetName()
    {
        //Some code...
        return _setName;
    }



}

継承されたサービスは次のようになります。

public class EmployeeService : ServiceBase<Employees>
{
    public EmployeeService(ObjectContext context)
        : base(context)
    {

    }

}

public class DepartmentService : ServiceBase<Departments>
{
    private readonly EmployeeService _employeeService;

    public DepartmentService(ObjectContext context, EmployeeService employeeService) : base(context)
    {
        _employeeService = employeeService;
    }

    public IList<Departments> DoSomethingWithEmployees(string lastName)
    {
        //won't work because method with this signature is not visible to this class
        var emps = _employeeService.GetAll(true);

        //more code...
    }
}

親クラスのライブは再利用可能であるため、子サービスとは別のアセンブリに存在します。GetAll(bool returnQueryable) が internal としてマークされていると、子は互いの GetAll(bool) メソッドを見ることができず、public GetAll() メソッドだけを見ることができません。

アセンブリ内の各子サービスが互いのメソッドを認識できるように、新しい内部 GetAll メソッドを各サービス (ま​​たは同じアセンブリ内の中間の親クラス) に追加できることを知っています。しかし、機能は親クラスで既に利用可能であるため、不要のようです。

例えば:

    internal IEnumerable<Employees> GetAll(bool returnIQueryable)
    {
        return base.GetAll(returnIQueryable);
    }

基本的に私が望むのは、サービスが IQueryable として他のサービス メソッドにアクセスできるようにすることです。これにより、コミットされていない結果をさらに絞り込むことができ、他のすべての人は単純な古いリストを取得できます。

何か案は?

編集

ご存知のように、私はこれを使ってちょっとしたコード ゴルフを楽しんでいましたが、クラスではなくインターフェイスを渡しているため、最終的にはこのスキームを使用することはできません。

したがって、私の例では GetAll(bool returnIQueryable) はインターフェイスに含まれていません。つまり、キャストを行う必要があり、これは私が達成しようとしていることに反します。

脳のおならがあったのか、それともうまくいくと思ったものを手に入れようとして興奮しすぎたのかはわかりません. いずれにせよ、応答に感謝します。

4

3 に答える 3

3

メソッドを公開するという明白な答えの何が問題になっていますか?

とにかくアクセシビリティは安全ではないので、「悪人」はリフレクションを使用して、あなたが付けた修飾子をバイパスする可能性があります. また、関連のない「兄弟」クラスからこれらのメソッドを呼び出したい場合は、「兄弟」アクセシビリティ修飾子がないため、これらのメソッドをパブリックにする必要があります。

別の提案:[assembly:InternalsVisibleTo("SomeOtherAssembly")]属性を適用して、他のビジネス ドメイン アセンブリに内部メンバーへのアクセスを許可します。

これにより、メンテナンスの負担が増え (アセンブリの名前を変更または追加した場合)、"魔法の文字列" が使用され、内部の本来の意味が無効になることに注意してください (すべての内部メンバーがこれらの他のアセンブリからも見えるようになるため)。

于 2010-04-08T22:04:21.500 に答える
0

おそらく私は何かが欠けていますが、あなたはそれをマークしてprotected internalあなたの目標を達成することができるはずです。

namespace Foo
{
    class A
    {
        protected internal void D() { Console.WriteLine(this.ToString() + " says 'Blah'"); }
    }
}

namespace Bar
{
    class B : Foo.A 
    {
        public B()
        {
        }
    }
}

namespace Baz
{
    class C : Foo.A
    {
        public C()
        {
            D();
            Bar.B b = new Bar.B();
            b.D();

            Foo.A a = new Foo.A();
            a.D();
        }
    }
}

出力を確認するには

Baz.C c = new Baz.C();

これはすべて合法的なコードです。Foo.Aがベースで、Bar.BとBaz.CはFoo.Aから継承しています。void DはAの保護された内部メンバーです。Baz.Cは期待どおりにD()を呼び出すことができ、Bar.BとFoo.Aのインスタンスを作成し、それらのD()メソッドも呼び出すことができます。

protected internalメンバーは、任意のアセンブリ内のすべての子孫クラスと、ベースと同じアセンブリ内のすべてのクラスに表示されます。アクセシビリティはそれらの範囲外で終了します。子と同じアセンブリ内の非子孫クラスは、メンバーを表示できません。

于 2010-04-08T23:59:36.847 に答える
0

子孫クラスが同じアセンブリに存在する場合、これは簡単になります。ただし、次の「トリック」は、クラスが別々のアセンブリに存在する場合 (インターフェイスのinternalキーワードを に変更する場合public) にも機能しますが、オブジェクトがキャストされていない場合にメソッドが呼び出されるのを防ぐだけです。たとえば、InheritedClassオブジェクトをにキャストするIBaseInterfaceと、誰でもGetValueメソッドを呼び出すことができます。これは本当に防ぐことはできません。なぜなら、あなたが望むことを実行できるキーワードの組み合わせがあったとしても、誰かがリフレクションを通じてメソッドを呼び出すことができるからです。

internal interface IBaseInterface {
    string GetValue();
}

public abstract class MyBase : IBaseInterface {
    string IBaseInterface.GetValue()
    { return "MyBase"; }
}

public class InheritedClass : MyBase {
    public void PrintValue(IBaseInterface someclass)
    { Console.WriteLine(someclass.GetValue()); }
}
于 2010-04-08T22:10:06.690 に答える