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

У меня есть (плохо написанный) базовый класс, который я хочу обернуть в прокси-объект. Базовый класс похож на следующее:

public class BaseClass : SomeOtherBase 
{
   public BaseClass() {}

   public BaseClass(int someValue) {}

   //...more code, not important here
}

и мой прокси напоминает:

public BaseClassProxy : BaseClass
{
  public BaseClassProxy(bool fakeOut){}
}

Без конструктора "fakeOut" ожидается, что будет создан базовый конструктор. Однако с этим я ожидал, что это не будет вызвано. В любом случае, мне либо нужен способ не называть конструкторы базового класса, либо каким-либо другим способом эффективно проксировать этот (злой) класс.

Ответы

Ответ 1

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

Ответ 2

Существует способ создания объекта без вызова каких-либо конструкторов экземпляров.

Прежде чем продолжить, будьте уверены, что хотите сделать это таким образом. 99% времени это неправильное решение.

Вот как вы это делаете:

FormatterServices.GetUninitializedObject(typeof(MyClass));

Вызовите его вместо конструктора объекта. Он создаст и вернет вам экземпляр без вызова каких-либо конструкторов или инициализаторов полей.

При десериализации объекта в WCF он использует этот метод для создания объекта. Когда это происходит, конструкторы и даже инициализаторы полей не запускаются.

Ответ 3

Необходимо вызвать не менее 1 ctor. Единственный путь, который я вижу, это сдерживание. Имейте класс внутри или ссылаясь на другой класс.

Ответ 4

Если вы хотите, чтобы не вызывал один из двух конструкторов базового класса, это невозможно.

Конструкторы класса С# должны вызывать конструкторы базового класса. Если вы не вызываете одно явно, подразумевается base(). В вашем примере, если вы не укажете, какой конструктор базового класса вызывать, это то же самое, что:

public BaseClassProxy : BaseClass
{
    public BaseClassProxy() : base() { }
}

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

public BaseClassProxy : BaseClass
{
    public BaseClassProxy() : base(someIntValue) { }
}

В любом случае, один из двух будет вызываться явно или неявно.

Ответ 5

Я не верю, что вы можете обойти вызов конструктора. Но вы можете сделать что-то вроде этого:

public class BaseClass : SomeOtherBase 
{
   public BaseClass() {}

   protected virtual void Setup()
   {
   }
}

public BaseClassProxy : BaseClass
{
   bool _fakeOut;
   protected BaseClassProxy(bool fakeOut)
   {
        _fakeOut = fakeOut;
        Setup();
   }

   public override void Setup()
   {
       if(_fakeOut)
       {
            base.Setup();
       }
       //Your other constructor code
   }
} 

Ответ 6

Я боюсь, что базовый вызывающий конструктор не является опцией.

Ответ 7

Когда вы создаете объект BaseClassProxy, НУЖНО создавать экземпляр базового класса, поэтому вам нужно вызвать конструктор базового класса, что вы можете сделать, выбрав тот, который вы хотите вызвать, например:

public BaseClassProxy (bool fakeOut) : base (10) {}

Чтобы вызвать второй конструктор вместо первого

Ответ 8

В итоге я сделал что-то вроде этого:

public class BaseClassProxy : BaseClass 
{
   public BaseClass BaseClass { get; private set; }

   public virtual int MethodINeedToOverride(){}
   public virtual string PropertyINeedToOverride() { get; protected set; }
}

Это привело меня к некоторым неправильным действиям базового класса.

Ответ 9

Конструкторы

являются общедоступными. не используйте конструктор и не используйте другое для построения и не делайте его private.so вы создадите экземпляр без параметров и вызовите эту функцию для создания экземпляра объекта.

Ответ 10

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

Вот мой конструктор класса:

public MyClass();
{
   throw new Exception("Error: Must call constructor with parameters.");
}

Хорошо, теперь вы были предупреждены, что это было некрасиво. Без претензий, пожалуйста!

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

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

Ответ 11

Можно создать объект без вызова конструктора без параметров (см. Ответ выше). Но я использую такой код для создания базового класса и унаследованного класса, в котором я могу выбрать, выполнять ли базовый класс init.

public class MyClass_Base
{
    public MyClass_Base() 
    {
        /// Don't call the InitClass() when the object is inherited
        /// !!! CAUTION: The inherited constructor must call InitClass() itself when init is needed !!!
        if (this.GetType().IsSubclassOf(typeof(MyClass_Base)) == false)
        {
            this.InitClass();
        }
    }

    protected void InitClass()
    {
        // The init stuff
    }
}


public class MyClass : MyClass_Base
{
    public MyClass(bool callBaseClassInit)
    {
        if(callBaseClassInit == true)
            base.InitClass();
    }
}

Ответ 12

Вот мое решение проблемы

using System;

public class Program
{
    public static void Main()
    {
        Console.WriteLine(new Child().Test);
    }

    public class Child : Parent {
        public Child() : base(false) {
            //No Parent Constructor called
        }
    }
    public class Parent {
        public int Test {get;set;}
        public Parent()
        {
            Test = 5;
        }
        public Parent(bool NoBase){
            //Don't do anything
        }
    }
}

Простое элегантное решение. Вы можете изменить его в соответствии с вашими потребностями.