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

本文关键字:异常 实例 引用 构造函数 获取 | 更新日期: 2023-09-27 17:49:23

考虑以下问题

在设计框架时,提供一个暴露某些事件的接口

interface I
{
  event MyEventHandler MyEvent
}

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

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

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不那么用户友好。当每个事件实参的参数数量增加时,这会变得更加麻烦。

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

是否有可能获得构造函数抛出异常的实例的引用并将其传递给事件侦听器?

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

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

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

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

做正常的事。不过,你把这件事想清楚了,这很好。

是否有可能获得构造函数抛出异常的实例的引用并将其传递给事件侦听器?

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

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

千万别那么做。无论如何,这是不自然的代码。对象的构造函数通常不应该做太多事情,它应该使对象进入有效状态,并且不会产生副作用。副作用是发布this引用的唯一方法。

还有一个问题:如果存在终结器,将在该对象上调用终结器。终结器很少使用,因为大多数情况下,非托管资源应该由句柄类持有。由于这个原因,这个问题很少生效。但是终结器可以看到它的对象的私有状态。确保它能处理这个。

FileStream的终结器可能会检查初始化是否被终止而不做任何事情。

客户端必须检查HasValue,然后访问Value

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

是否有可能获得对构造函数抛出异常的实例的引用

不,当构造函数抛出异常时,你不会得到一个实例。

来回答你的问题。不。如果在构造函数

中遇到错误,则不能使结果为空。

然而,我认为最好的方法是在MyEventArgs类中添加一个静态构造函数

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);来使用构造器目录

在多个事件参数上使用这个方法有点压力,但是嘿:)你总是可以从同一个通用抽象类中派生出所有的事件参数

希望这对你有帮助