Сведения о вопросе

Junior

03:01, 3rd August, 2020

Теги

c#   inheritance   oop    

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

Просмотров: 551   Ответов: 9

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

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

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

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
{
}

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

ОБНОВЛЕНИЕ
Мне не нужно обращаться к каким-либо конкретным методам ConcreteClassA или B из-за пределов абстрактного класса. Мне нужны только общедоступные методы, которые предоставляет мой абстрактный класс. Мне действительно не нужно предотвращать создание экземпляров конкретных классов, я просто пытаюсь избежать этого, поскольку они не предоставляют новых открытых интерфейсов, а просто разные реализации некоторых очень специфических вещей, внутренних для абстрактного класса.

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

Я думаю, что нет простого решения для этого...



  Сведения об ответе

piter

12:51, 27th August, 2020

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

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

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

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

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 (string args)

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()
    {
    }
}


  Сведения об ответе

nYU

14:27, 15th August, 2020

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


  Сведения об ответе

park

16:35, 22nd August, 2020

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

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: как уже упоминалось, то же самое можно сделать с помощью отражения, которое на самом деле может быть ближе к тому, что вы хотели бы иметь - например, приведенный выше метод отвечает на конкретные классы, находящиеся внутри того же файла, что и абстрактный класс, что, вероятно, не очень удобно. Сказав, что этот способ является хорошим 'Hack', и хорошо, если количество и сложность конкретных классов невелики.


  Сведения об ответе

screen

23:28, 4th August, 2020

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


  Сведения об ответе

dumai

14:14, 21st August, 2020

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


  Сведения об ответе

ITSME

22:21, 23rd August, 2020

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

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() {}
}


  Сведения об ответе

#hash

22:03, 21st August, 2020

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

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


  Сведения об ответе

crush

11:05, 21st August, 2020

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


  Сведения об ответе

P_S_S

20:47, 22nd August, 2020

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

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

}


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться