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

StackOverflow https://stackoverflow.com/questions/20185

  •  09-06-2019
  •  | 
  •  

Вопрос

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

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

Я бы хотел сделать это в принципе

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() может создавать экземпляры базовых классов.Есть ли какой-нибудь способ сделать это?

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

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

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

Это было полезно?

Решение

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

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

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

Другие советы

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

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

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

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

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

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

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

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

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

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

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

Если вы используете этот класс в отдельной сервисной сборке, вы можете использовать ключевое слово 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() {}
}

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

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

}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top