2010-04-08 4 views
2

Я пытаюсь получить доступ к методу, который помечен как внутренний в родительском классе (в его собственной сборке) в объекте, который наследуется от одного и того же родителя.Как получить доступ к внутреннему методу объекта-потомка в C#

Позвольте мне объяснить, что я пытаюсь сделать ...

Я хочу, чтобы создавать классы службы, которые возвращают IEnumberable с основной список для классов неслужебную (например, UI) и необязательно возвращать IEnumerable с базовый IQueryable для других сервисов.

Я написал несколько примеров кода, чтобы продемонстрировать, что я пытаюсь выполнить, как показано ниже. Пример не в реальной жизни, поэтому, пожалуйста, помните, что при комментировании.

Все услуги будут наследовать от чего-то вроде этого (только соответствующий код показан):

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) будет помечен как внутреннее, дети не смогут увидеть метод GetAll (bool) друг друга, а только общедоступный метод GetAll().

Я знаю, что я могу добавить новый внутренний метод GetAll для каждой службы (или, возможно, промежуточного родительского класса в рамках одной и той же сборки), чтобы каждый дочерний сервис внутри сборки мог видеть метод друг друга; но это кажется ненужным, поскольку функциональность уже доступна в родительском классе.

Например:

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

По сути то, что я хочу, чтобы услуги, чтобы иметь возможность получить доступ к другим методам обслуживания, как IQueryable, так что они могут дополнительно уточнить неподтвержденные результаты, в то время как все остальные получают простые старые списки.

Любые идеи?

EDIT

Вы знаете, что у меня было немного весело играть немного кода в гольф с этим ... но в конечном счете, я не смог бы использовать эту схему в любом случае, потому что я прохожу интерфейсы вокруг, а не классы ,

Так что в моем примере GetAll (bool returnIQueryable) не будет в интерфейсе, то есть мне придется делать кастинг, что противоречит тому, что я пытаюсь выполнить.

Я не уверен, что у меня был мозговой пердит, или если я был просто слишком возбужден, пытаясь получить то, что, как я думал, было аккуратно работать. В любом случае, спасибо за ответы.

ответ

3

Что не так с очевидным ответом на то, чтобы сделать этот метод общедоступным?

Доступность в любом случае небезопасна, поэтому «злые люди» могут использовать отражение, чтобы обойти любой модификатор, который вы надели. И так как вы хотите называть эти методы из несвязанных «родственных» классов, они должны быть общедоступными, так как нет модификатора доступности «родного брата».

Альтернативное предложение: примените атрибут [assembly:InternalsVisibleTo("SomeOtherAssembly")], чтобы предоставить другим узлам бизнес-домена доступ к внутренним членам.

Обратите внимание, что это добавляет нагрузку на обслуживание (если вы переименовываете или добавляете сборки), использует «магические строки» и отрицает исходное значение внутреннего (так как теперь все внутренние члены будут видны и для этих других сборок).

+0

Я не пытаюсь скрыться от «злых людей», наша политика заключается в том, что бизнес-уровень должен возвращать списки на вышеуказанный уровень. Если услуги возвращают iqueryables друг другу, это делает вещи немного более удобными в бизнес-слое. –

+0

Вы можете использовать атрибут «protected internal» и InternalsVisibleTo, чтобы предоставить конкретным узлам доступ к внутренним членам, если вам это очень нравится. Я бы рекомендовал против него, поскольку он должен поддерживаться (например, если вы добавляете другую сборку или решаете переименовать ее), но может быть решением для вас. –

+0

Я считал InternalsVisible, но я не думаю, что это сработает для меня. Я, вероятно, не уточнил первоначальный вопрос; базовый класс будет использоваться многими различными проектами разных команд в компании; поэтому было бы очень странно иметь в базовом классе десятки атрибутов InternalsVisible. Мне нужна противоположность этому, когда аутсайдеры «выбирают», чтобы получить доступ к методу. Я уверен, что этого не существует. Спасибо за предложение! –

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()); } 
} 
+0

Да, этот альтернативный вид обрабатывает его с другой стороны в качестве альтернативы, которую я предоставил в вопросе (иметь базовый класс, который наследуется от исходного класса, чтобы все дочерние классы из одной и той же сборки могли видеть внутренние методы друг друга). Я вроде хотел избежать дополнительной работы, но я не думаю, что это возможно. –

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 элементы видны для всех классов потомков в любой сборке и всех классах внутри той же сборки, что и база. Доступность заканчивается за пределами этих границ. Не-потоковые классы в тех же сборках, что и дети, не смогут увидеть участника.

+0

Я хочу объекты, которые совместно используют предок, чтобы иметь доступ к методу друг друга. Эти классы будут определены другим предком как базовый класс. –

+0

Являются ли эти методы * другими *, чем те, которые наследуются? Как я уже сказал, братья и сестры смогут увидеть унаследованные методы друг друга, если они по меньшей мере классифицируются как защищенные. С другой стороны, непривилегированные методы должны быть общедоступными, чтобы быть видимыми в сборках. –

Смежные вопросы