Вызов метода экземпляра без вызова конструктора - PullRequest
1 голос
/ 18 ноября 2009

Допустим, у меня есть следующий класс, который мне запрещено изменять:

public class C
{
    public C() { CreateSideEffects(); }
    public void M() { DoSomethingUseful(); }
}

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

Ответы [ 5 ]

8 голосов
/ 18 ноября 2009

Даже если это НЕ ХОРОШАЯ ИДЕЯ , да, мы можем;) с FormatterServices. GetUninitializedObject .

C uninitializedC = (C)FormatterServices.GetUninitializedObject(typeof(C));
uninitializedC.M();
7 голосов
/ 18 ноября 2009

Нет. Поскольку C.M() является методом экземпляра, вам нужно создать экземпляр, что означает вызов конструктора.

Является ли C классом, которым владеет ваша команда? Если это так, но у вас есть приказ оставить его в покое, вы бы неплохо лоббировали:

  1. Те побочные эффекты, которые должны быть переработаны и удалены
  2. Функциональность метода C.M() перемещена в другой класс или сделана статической.

Если C от стороннего производителя, у вас возникнут проблемы, и вам, возможно, придется скопировать функциональность C.M() в методе, которым вы делаете .

4 голосов
/ 18 ноября 2009

Да, вы можете!

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

РЕДАКТИРОВАТЬ: Просто понял, что мой пример использует Java, а не C #. Тем не менее, @Guillaume предлагает пример кода для C #. По-видимому, он даже встроен в API времени выполнения!

В Java, с Mockito , это работает:

C c = Mockito.mock(C);
Mockito.doCallRealMethod().when(c).M();
// If M() isn't a void method
// when(c.M()).thenCallRealMethod();
c.M();

Однако в этом случае M() не может зависеть от какого-либо состояния, установленного в конструкторе.

Для получения дополнительной информации о частичной насмешке, посмотрите этот FAQ Вопрос Тем не менее, насмешка в основном используется для тестирования.

1 голос
/ 18 ноября 2009

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

using System.Runtime.Serialization;

    C myInstance = FormatterServices.GetUninitializedObject(typeof(C));
    myInstance.M();

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

Опять плохая идея в целом;)

1 голос
/ 18 ноября 2009

Чтобы вызвать метод экземпляра, вам нужен экземпляр! И - по веским причинам - единственный способ получить его - через конструктор. В противном случае весь объект может находиться в неопределенном или бесполезном состоянии, поскольку инициализация не была выполнена. Так что, даже если бы был какой-то взлом, это был бы совсем не хороший выбор!

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

...