假设我有以下课程,我不允许改变:
public class C
{
public C() { CreateSideEffects(); }
public void M() { DoSomethingUseful(); }
}
我必须在不调用构造函数的情况下调用M.有可能吗?
答案 0 :(得分:8)
即使它是不是一个好的想法,是的,我们可以;) 与FormatterServices.GetUninitializedObject。
C uninitializedC = (C)FormatterServices.GetUninitializedObject(typeof(C));
uninitializedC.M();
答案 1 :(得分:7)
没有。因为C.M()
是一个实例方法,所以需要创建一个实例,这意味着调用构造函数。
C
是您的团队拥有的课程吗?如果确实如此,但你有责任不管它,那么你最好还是游说:
C.M()
方法功能移出到另一个类或静态。如果C
来自第三方,您将遇到麻烦,可能需要在执行拥有的方法中复制C.M()
的功能
答案 2 :(得分:4)
是的,你可以!
毋庸置疑,这是一个糟糕的设计,但你已经知道并且无法改变它。如果必须,你可以尝试局部嘲笑这个班级。
编辑:刚才意识到我的例子使用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 Question。但是,模拟主要用于测试。
答案 3 :(得分:1)
为了调用实例方法,您需要一个实例!并且 - 有充分的理由 - 获得一个的唯一方法是通过构造函数。否则整个对象可能处于不确定或无用状态,因为尚未进行初始化。所以,即使有某种黑客攻击,也不是一个好的选择!
没有实例可以调用的唯一类成员是静态方法。
答案 4 :(得分:1)
我不会告诉你这是一个坏主意,因为听起来你已被告知足够了。哦,对不起我想我刚刚做了......无论如何这里是怎么做的:
using System.Runtime.Serialization;
C myInstance = FormatterServices.GetUninitializedObject(typeof(C));
myInstance.M();
上面的'GetUninitializedObject'方法返回一个对象的实例而不调用任何实例ctor(显然任何静态类型的ctor仍然会运行)。然后,您可以根据需要戳实例字段,或者只是调用方法。
再次,整体上是一个坏主意;)