Есть ли способ сделать конструктор видимым только для родительского класса в C #? - PullRequest
5 голосов
/ 21 августа 2008

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

Есть ли способ скрыть конструктор от всего кода, кроме родительского класса.

Я бы хотел сделать это в основном

public abstract class AbstractClass
{
    public static AbstractClass MakeAbstractClass(string args)
    {
        if (args == "a")
            return new ConcreteClassA();
        if (args == "b")
            return new ConcreteClassB();
    }
}

public class ConcreteClassA : AbstractClass
{
}

public class ConcreteClassB : AbstractClass
{
}

Но я хочу помешать кому-либо непосредственно создавать экземпляры двух конкретных классов. Я хочу убедиться, что только метод MakeAbstractClass () может создавать экземпляры базовых классов. Есть ли способ сделать это?

UPDATE
Мне не нужно обращаться к каким-либо конкретным методам ConcreteClassA или B извне класса Abstract. Мне нужны только открытые методы, которые предоставляет мой класс Abstract. На самом деле мне не нужно предотвращать создание экземпляров классов Concrete, я просто пытаюсь избежать этого, поскольку они не предоставляют никаких новых открытых интерфейсов, а представляют собой просто разные реализации некоторых очень специфических вещей, внутренних по отношению к абстрактному классу.

Для меня самое простое решение - создать дочерние классы, как упомянул Самджудсон . Однако я бы хотел этого избежать, так как это сделало бы файл моего абстрактного класса намного больше, чем хотелось бы. Я бы лучше разделил классы на несколько файлов для организации.

Полагаю, нет простого решения ...

Ответы [ 9 ]

6 голосов
/ 21 августа 2008

Для меня самое простое решение - сделать дочерние классы как самюдсон упоминается. Я хотел бы избежать этого Однако так как это сделало бы мой абстрактный класс 'файл намного больше, чем Я бы хотел, чтобы это было. Я бы предпочел сохранить классы разделены на несколько файлов для организация.

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

Предыдущий ответ:

Это возможно, но только с отражением

public abstract class AbstractClass
{
    public static AbstractClass MakeAbstractClass(string args)
    {
        if (args == "a")
            return (AbstractClass)Activator.CreateInstance(typeof(ConcreteClassA), true);
        if (args == "b")
            return (AbstractClass)Activator.CreateInstance(typeof(ConcreteClassB), true);
    }
}

public class ConcreteClassA : AbstractClass
{
    private ConcreteClassA()
    {
    }
}

public class ConcreteClassB : AbstractClass
{
    private ConcreteClassB()
    {
    }
}

а вот еще один шаблон, без уродливого MakeAbstractClass (строковые аргументы)

public abstract class AbstractClass<T> where T : AbstractClass<T>
{
    public static T MakeAbstractClass()
    {
        T value = (T)Activator.CreateInstance(typeof(T), true);
        // your processing logic
        return value;
    }
}

public class ConcreteClassA : AbstractClass<ConcreteClassA>
{
    private ConcreteClassA()
    {
    }
}

public class ConcreteClassB : AbstractClass<ConcreteClassB>
{
    private ConcreteClassB()
    {
    }
}
3 голосов
/ 21 августа 2008

Если классы находятся в одной сборке, вы не можете сделать конструкторы внутренними?

2 голосов
/ 21 августа 2008

Вы можете сделать подклассы дочерними классами, примерно так:

public abstract class AbstractClass
{
    public static AbstractClass MakeAbstractClass(string args)
    {
        if (args == "a")
            return new ConcreteClassA();
        if (args == "b")
            return new ConcreteClassB();
    }

    private class ConcreteClassA : AbstractClass
    {
    }

    private class ConcreteClassB : AbstractClass
    {
    }
}

@ Vaibhav Это действительно означает, что классы также скрыты. Но это, насколько я знаю, единственный способ полностью скрыть конструктор.

Edit: как уже упоминалось, то же самое можно сделать с помощью Reflection, что на самом деле может быть ближе к тому, что вы хотели бы иметь, например, вышеупомянутый метод отвечает на конкретные классы, находящиеся внутри того же файла, Абстрактный класс, что, вероятно, не очень удобно. Сказав, что этот способ - хороший «хак», он хорош, если количество и сложность конкретных классов невелики.

1 голос
/ 10 сентября 2008

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

1 голос
/ 21 августа 2008

Нет, я не думаю, что мы можем сделать это.

0 голосов
/ 23 августа 2008

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

public class AbstractClass
{
    public AbstractClass ClassFactory(string args)
    {
        switch (args)
        {
            case "A":
                return new ConcreteClassA();               
            case "B":
                return new ConcreteClassB();               
            default:
                return null;
        }
    }
}

public class ConcreteClassA : AbstractClass
{
    internal ConcreteClassA(){ }
}

public class ConcreteClassB : AbstractClass
{
    internal ConcreteClassB() {}
}
0 голосов
/ 21 августа 2008

Разве вы не можете использовать ключевое слово partial для разбиения кода класса на множество файлов?

0 голосов
/ 21 августа 2008

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

public abstract class AbstractClass{

 public static AbstractClass MakeAbstractClass(string args)
 {
    if (args == "a")
        return ConcreteClassA().GetConcreteClassA();
    if (args == "b")
        return ConcreteClassB().GetConcreteClassB();
 }
}

public class ConcreteClassA : AbstractClass
{
  private ConcreteClassA(){}

  internal static ConcreteClassA GetConcreteClassA(){
       return ConcreteClassA();
  }
}

public class ConcreteClassB : AbstractClass
{
  private ConcreteClassB(){}
  internal static ConcreteClassB Get ConcreteClassB(){
       return ConcreteClassB();
  }

}
0 голосов
/ 21 августа 2008

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

Если вам не нужно этого делать, просто реализуйте настоящий фабричный шаблон. Или, более ALTy, используйте платформу DI / IoC.

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