Есть ли способ скрыть методы частично в дочерних классах? - PullRequest
6 голосов
/ 16 февраля 2010

Этот вопрос кажется странным, но я недавно сталкивался с этим вопросом в одном из интервью.

Меня спросили, есть ли способ в c # скрыть методы частично в унаследованных дочерних классах ?. Предположим, базовый класс А, выставлено 4 метода. Класс B реализует A, и он будет иметь доступ только к первым двум методам, а класс C реализует A только к последним 2 методам.

Я знаю, что мы можем сделать это

public interface IFirstOne
{
    void method1();        
    void method2();
}

public interface ISecondOne
{
    void method3();
    void method4();
}

class baseClass : IFirstOne, ISecondOne
{
    #region IFirstOne Members

    public void method1()
    {
        throw new NotImplementedException();
    }

    public void method2()
    {
        throw new NotImplementedException();
    }

    #endregion

    #region ISecondOne Members

    public void method3()
    {
        throw new NotImplementedException();
    }

    public void method4()
    {
        throw new NotImplementedException();
    }

    #endregion
}

class firstChild<T> where T : IFirstOne, new()
{
    public void DoTest() 
    {

        T objt = new T();
        objt.method1();
        objt.method2();
    }
}


class secondChild<T> where T : ISecondOne, new()
{
    public void DoTest() 
    {
        T objt = new T();
        objt.method3();
        objt.method4();
    }
}

Но то, что они хотели, это другое. Они хотели скрыть эти классы при наследовании от базовых классов. как то так

class baseClass : IFirstOne, ISecondOne
{
    #region IFirstOne Members

    baseClass()
    {
    }

    public void method1()
    {
        throw new NotImplementedException();
    }

    public void method2()
    {
        throw new NotImplementedException();
    }

    #endregion

    #region ISecondOne Members

    public void method3()
    {
        throw new NotImplementedException();
    }

    public void method4()
    {
        throw new NotImplementedException();
    }

    #endregion
}

class firstChild : baseClass.IFirstOne //I know this syntax is weird, but something similar in the functionality
{
    public void DoTest() 
    {
        method1();
        method2();

    }
}


class secondChild : baseClass.ISecondOne
{
    public void DoTest() 
    {           
        method3();
        method4();
    }
}

Есть ли способ в C #, мы можем достичь чего-то вроде этого ...

Ответы [ 6 ]

3 голосов
/ 16 февраля 2010

Я сделал это, имея 1 основной базовый класс и 2 подосновы.

// Start with Base class of all methods
public class MyBase
{
    protected void Method1()
    {

    }

    protected void Method2()
    {

    }

    protected void Method3()
    {

    }

    protected void Method4()
    {

    }
}

// Create a A base class only exposing the methods that are allowed to the A class
public class MyBaseA : MyBase
{
    public new void Method1()
    {
        base.Method1();
    }

    public new void Method2()
    {
        base.Method2();
    }
}

// Create a A base class only exposing the methods that are allowed to the B class
public class MyBaseB : MyBase
{
    public new void Method3()
    {
        base.Method3();
    }

    public new void Method4()
    {
        base.Method4();
    }
}

// Create classes A and B
public class A : MyBaseA {}

public class B : MyBaseB {}

public class MyClass
{
    void Test()
    {
        A a = new A();

        // No access to Method 3 or 4
        a.Method1();
        a.Method2();

        B b = new B();

        // No Access to 1 or 2
        b.Method3();
        b.Method4();


    }
}
2 голосов
/ 16 февраля 2010

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

0 голосов
/ 16 февраля 2010

А как насчет внедрения базового класса как IFirst?

interface IFirst {
    void method1();
    void method2();
}

interface ISecond {
    void method3();
    void method4();
}

abstract class Base : IFirst, ISecond {
    public abstract void method1();
    public abstract void method2();
    public abstract void method3();
    public abstract void method4();
}

class FirstChild : IFirst {
    private readonly IFirst _first;
    public FirstChild(IFirst first) {
        _first = first;
    }
    public void method1() { _first.method1(); }
    public void method2() { _first.method2(); }
}

Инъекция удерживает вас от нарушения Принципа разделения интерфейса .Чистое наследование означает, что ваш FirstChild зависит от интерфейса, который он не использует.Если вы хотите сохранить только функциональность IFirst в Base, но игнорировать остальную ее часть, то вы не можете просто наследовать от Base.

0 голосов
/ 16 февраля 2010

Существует 2 решения для скрытия методов, унаследованных от базового класса:

  • Как упомянуто thecoop, вы можете явно реализовать интерфейс, объявляя методы, которые вы хотите скрыть.
  • Или вы можете просто создать эти методы в базовом классе (не наследуемом от какого-либо интерфейса) и пометить их как частные.

Привет.

0 голосов
/ 16 февраля 2010

Не используйте наследование. Он делает общедоступные или защищенные средства базового класса доступными непосредственно в производном классе, поэтому он просто не хочет, чтобы вы хотели.

Вместо этого заставьте производный класс реализовать соответствующий интерфейс и (при необходимости) перенаправить методы в частный экземпляр базового класса. То есть используйте состав (или «агрегацию») вместо наследования для расширения исходного класса.

class firstChild : IFirstOne 
{
    private baseClass _owned = new baseClass();

    public void method1() { _owned.method1(); }
    // etc.
}

Кстати, имена классов должны начинаться с заглавной буквы.

0 голосов
/ 16 февраля 2010

Возможно, интервьюер имел в виду метод сокрытия ?

Здесь вы объявляете метод с той же сигнатурой, что и в вашем базовом классе - но вы не используете ключевое слово override (либо потому, что вы этого не делаете, либо не можете - как в случае метода в базовый класс не является виртуальным).

Скрытие метода, в отличие от переопределение , позволяет определить совершенно другой метод - тот, который вызывается только через ссылку на производный класс. Если вызывается через ссылку на базовый класс, вы вызовете оригинальный метод базового класса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...