如何确定谁是对象的创建者
调用构造函数时存储堆栈跟踪。这与SlimDX在调试版本中所做的相似。
依靠堆栈的一个警告: 它可以并且将根据优化等调试+发布模式不同。我最近不得不修复一个类,它会在发布模式中输出错误的信息 - 它对数字进行了假设堆栈帧来遍历以获取调用者。但是,JIT酌情考虑了各种电话。因此,调试和发布模式功能不一致。 只是要注意的东西:) – 2009-08-31 00:09:31
我知道,但这正是你可以从堆栈跟踪。在这种情况下,程序的行为并不依赖于追踪,只依赖技术支持。我相信引用类型构造函数不会内联,但其他方法应该用'[MethodImpl(MethodImplOptions.NoInline)]'装饰(如果我正确记住了“拼写”)。 – 2009-08-31 00:25:26
我可能失去了一些东西,但我敢肯定,你能做到这一点,唯一的办法就是通过手动传递这些信息,FE。在你的对象的构造函数中。
编辑:如果这是你在找什么? :
class Creator
{
public string Name { get; private set; }
public Creator(string name)
{
Name = name;
}
}
class Foo
{
readonly Creator creator;
public Foo(Creator creator)
{
this.creator = creator;
}
public void DoSth()
{
throw new Exception("Unhandled exception. My creator is " + creator.Name);
}
}
public static void Main()
{
Foo f = new Foo(new Creator("c1"));
f.DoSth();
}
-1这真的不是一个好方法。首先,它会以令人困惑和不合时宜的参数污染构造函数。如果我有一个在其构造函数中使用了customerId参数的BankAccount类,那么名为,creatorName等的额外参数会如何看起来如何?这会令人困惑。其次,如果创建者类被重命名?现在,除非您记住在整个代码库中更改创建者名称,否则您的创建者信息不正确。您可以使用类型信息来传递名称,但现在您需要确保每个人都这样做。 – 2009-08-30 15:13:13
污染ctor - 是的,这是一个问题,重命名 - 不,这没有问题。在这个简单的例子中,我使用了一些自定义字符串,但通常情况下,您只需使用反射来获取类的名称,所以它就可以工作。但再次 - 如果你想能够区分少数具有公共类的创建者对象,那么你需要给它们定制名称,所以完整的解决方案将使用一些自定义属性+使用反射来获取类的名称。至于第一个问题,堆栈跟踪的解决方案可能会更好,您的权利。 – 2009-08-30 15:18:55
一种选择将是把 “父” 引用到对象:
MyObject myObj = new MyObject(this);
,然后使用它。
如果仅用于调试目的,则将类本地字符串字段添加到类中,并在类构造函数中为其分配Environment.StackTrace
。然后,您也可以在例外中包含这些信息。
我建议使用StackTrace
对象和/或它的GetFrame
方法。我没有尝试过,但它应该做你所需要做的事情,而不必改变对象的每个实例(假设你没有使用Factory)。
我想象一下similar to this会起作用。
using System.Diagnostics;
// get call stack
StackTrace stackTrace = new StackTrace();
// get calling method name
Console.WriteLine(stackTrace.GetFrame(1).GetMethod().Name);
另请注意,这似乎是“不完全”重复,但它接近上面链接的问题。
您可以尝试在对象的构造函数中从堆栈跟踪中收集一些信息。您可以获得堆栈帧StackTrace.GetFrames。然后,您可以走栈并尝试获取某个方法所属的类型。如果该类型与对象类型不同,则停止步行并将该类型信息存储在对象中。然后,当发生异常时,您可以将该信息与异常一起包含在内。
请注意,这会增加实例化对象的成本。所以你应该考虑这一点,并且可能会被放入一个机制来启用/禁用它,或者只在调试版本中包含这段代码。
@塞西尔的建议其实更好。与其采取在构造函数中获取创建者信息的热切方法,不如采取一种懒惰的方法,并且仅在需要这些信息时才付出代价。换句话说,只需在构造函数中捕获和存储堆栈跟踪,并迭代堆栈帧以仅在需要时才获取创建者信息,例如发生异常时。一旦你有了这些信息,你也应该保留这些信息以防再次使用。 – 2009-08-30 15:22:18
像这样的事情可以努力获取调用类型:
public class Foo
{
private Type ParentAtCreation = null;
public Foo()
{
ParentAtCreation = (new StackTrace())
.GetFrame(1)
.GetMethod()
.DeclaringType;
}
}
您可以使用重载的构造函数到类和一个全局变量来存储您在重载的构造
收到一封该对象。g如果你想在WinForms中创建一个类的对象,当你调用要创建的对象时,你需要使用一个重载的构造函数来接收一个形式对象
并且在构造函数中使用这个对象来存储它的值到全局变量中
在声明对象在这种情况下,我使用的一种形式使用我当前正在运行的形式,然后
Admin_Login ad = new Admin_Login(Enrol, this);
ad.Show();
this.Visible = false;
打开,使目前的形式不可见的再调用它时,我想它。我不能处理它作为新形式的其母公司现在
和Admin_Login形式我有一个重载的构造
public Admin_Login(string Enrol,Form parent)
{
Enrollment = Enrol;
Parent = parent;
InitializeComponent();
}
其中父是我的形式
的全局变量BOL
希望它给你一个想法,我现在正在处理这个问题,现在你理清你的问题...... – Mobin 2009-08-30 16:58:03
这个问题稍微含糊不清;它真的取决于你想要的。此调试信息是用于调试构建的,还是您将始终保留的东西?
如果它只是调试克鲁夫特,这将是在发布的产品删除,我建议做这样的事情,以减少你的类(ES)的污染:
移动创建到工厂将堆栈检查代码放在那里。这样,创建的类不需要关心堆栈框架的东西;它隐藏在工厂里。
然后,您可以通过属性设置器注入信息,如果您不介意有点污染,或者您可以让工厂更新每个实例的创建实例+关联创建信息的列表。然后你可以查询这个列表,直到你的心满意为止。最后,在发布版本中,您可以使用几个#ifdefs删除所有这些功能。
是的,你是对的,这只是为了找到一个预发布的问题。 我只是一个初学者,我非常确定什么是“将创作转化为工厂” - 请解释你是否有时间 – Brad 2009-08-30 23:34:16
工厂是一个专注于创建对象的类。它比通过构造函数简单创建对象有一些优点;如果每个人都通过工厂请求对象,则可以轻松地向其添加/删除调试代码并跟踪对象创建。代码将调试代码分散在各种基类/子类中,而不是将代码放在(大部分)一个地方。 它可能适合您的目的。 http://en.wikipedia.org/wiki/Factory_method_pattern – 2009-08-31 00:03:41
我很惊讶没有人这样说过,即使作为他们自己的解决方案的一个警告,所以我会:这通常是一个坏主意,如果你发现自己需要这样做,那通常是一个巨大的指出你的设计有些错误。如果你顺着这条路走下去解决你的问题,那么你最终会导致更大的问题。最好采取两个步骤,并修复使这种必要的设计。
我想找到问题 - 这只是为了调试。 – Brad 2009-08-30 23:32:39
你能否详细说明你的意思是“谁”?你想知道在哪个用户创建?或者什么类/功能? – 7wp 2009-08-30 13:59:39