获取对其构造函数抛出异常的实例的引用

Obtaining a reference to an instance whose constructor had thrown an exception

考虑以下问题

在设计框架时,会出现一个暴露一些事件的接口

interface I
{
  event MyEventHandler MyEvent
}

此接口最终将由许多不同的第 3 方供应商实现,并可能被各种客户端使用。

由于每个供应商都可能使用无效数据更新事件参数,作为框架作者,我唯一的控制权是在事件参数级别,所以我想到了以下模式:

class MyEventArgs
{

 public int? MyProperty{get;}

 MyEventArgs(int arg)
 {

   if(arg.IsInvalidArgument())//Let's pretend that there's such an extension method
     throw new ArgumentException(...)

   MyProperty = arg;
 }

这确保了客户端不能使用一些流氓代码提供的无效值,因为构造函数会抛出异常,因此整数将没有分配值,使其成为空引用。

然而,这也会在客户端代码中产生开销,因为现在客户端必须检查 HasValue 然后访问 Value,使得EventArgument 不太用户友好。当每个事件参数的参数数量增加时,这变得更加麻烦。

我可以在技术上删除问号,这将使客户摆脱 Nullable 的废话,因为在我看来,在上帝的绿色地球上没有办法获得对这样的一个实例,但问题是这个场景虽然很容易测试,但可能有我从未想过的边缘情况,因此我的问题。

是否有任何可能的方法来获取对其构造函数抛出异常的实例的引用并将其传递给事件侦听器?

回答你的问题。不,如果在构造函数中遇到错误,你不能得到空结果

但是我认为最好的解决方法是向 MyEventArgs 添加一个静态构造函数 class

public static int DEFAULT_ARG = 1;//you can set this to whatever you want
public static Create(int arg)
{
    if(checkArg(arg))
    {
        return new MyEventArgs(arg);
    }
    return new MyEventArgs(MyEventArgs.DEFAULT_ARG);
}

然后使用 var event = MyEventArgs.Create(arg);

而不是使用 var event = new MyEventArgs(arg); 的构造函数目录

在多个 eventargs 上使用这种方法有点压力,但是嘿 :) 你总是可以从同一个通用抽象中派生所有这些 class

希望这对您有所帮助:)

the client has to check the HasValue and then access Value

好吧,没必要将 属性 设为 Nullable<int>,因为您只能从构造函数中设置它(假设省略了 private set),它是不可空的.

Is there any possible way to obtain a reference to an instance whose constructor had thrown an exception

不,当构造函数抛出异常时,您不会返回实例。

当构造函数抛出异常时,没有办法获得对该对象的引用(除非对象通过分发 this before throwing; not可能,糟糕的设计)。

因此,您的无效值对象无法访问。它的状态确实是无效的(默认初始化)但没有人能看到它。这就像一个内部损坏的虚拟机并试图发射导弹但你禁用了虚拟网卡。

到处都在使用这种模式。你已经在不知不觉中使用了很多次。例如,如果您说 new FileStream(null),您将如何获得对该无效流的引用?你不能。

做正常的事。不过,你考虑清楚了,这很好。

Is there any possible way to obtain a reference to an instance whose constructor had thrown an exception and pass it to the event listeners?

没有。但这里有一个可能的例子:

class C {
 public static C Instance; 
 public C() {
  Instance = this; //publish/leak
  throw ...;
 }
}

只是不要那样做。无论如何,这是不自然的代码。对象的构造函数通常不应该做太多,它应该使对象进入有效状态并且不会引起副作用。副作用是发布对 this.

的引用的唯一方法

还有一个问题:如果存在终结器,则将对该对象调用终结器。终结器很少见,因为大多数时候非托管资源应该由句柄 类 持有。出于这个原因,这个问题很少生效。但是终结器可以看到其对象的私有状态。确保它可以处理这个问题。 FileStreams finalizer 可能会检查异常中止的初始化并且什么也不做。