0

我正在寻找一种方法来创建一个具有默认公共构造函数的类,但这禁止它在反射之外使用。

更详细地说,我正在使用一个对象持久性框架(AWS DynamoDB - 我没有更改的选项),它要求对象实现这样的公共默认构造函数。该框架还要求所有持久化字段和属性也具有公共 get 和 set 访问器,并在创建和初始化新对象实例时使用它们。这会导致问题,因为访问器需要服务于双重目的——它们在被框架使用时需要“裸露”,但在被代码使用时需要强制限制和验证。无论如何,我已经解决了这部分问题,但它依赖于永远不允许代码使用默认构造函数(持久性框架使用的构造函数)构造持久化对象。

回到最初的问题 - 为了使这一切正常工作,我需要禁止代码使用默认构造函数,同时仍使其可供持久性框架使用(仅搜索空的公共构造函数)。我开始使用静态标志并在任何潜在的对象持久性使用之前和之后设置它,如果未设置,则在默认构造函数中抛出异常,但这开始在多线程环境(Web服务器)中引起问题)。一个线程会将它设置为供持久性框架使用,这将打开构造函数供其他线程使用。我还尝试了一个 ThreadStatic 标志,但它有阻止框架构建的相反问题,因为它有时会产生工作线程。

现在我想知道是否真的有办法做到这一点。在这一点上,它变得更像是一种好奇心而不是一种要求。我总是可以按照“不要使用这个构造器”的方式写一个评论,但是直接执行规则会让我感觉更好。我以前使用过 PostSharp,也许有一种方法可以使用方面进行编译时验证,以防止使用基于代码的默认构造函数?还有其他建议吗?

4

2 回答 2

1

我不会在这上面花太多时间。不会有一种“干净”的方式来做到这一点,而且你会浪费大量的周期来尝试。让调用者负责使用,只需明智地注释您的代码。

WinForms 中也会出现同样的问题,即要求 Forms 中的无参数构造函数来支持 VS 设计器,而在正常使用 Form 时,调用者必须提供某些参数(例如,要显示的输入数据集)。

如果你真的想要,一种方法可能是在默认构造函数中使用反射来确定调用者,如果调用者程序集不是 DynamoDB,则抛出异常;

if (!Assembly.GetCallingAssembly().FullName.Contains("DynamoDB"))
    throw new InvalidOperationException("BEGONE!");

另外,作为旁注,我通常将这些类型的“开发人员”检查实现为 Debug.Asserts,而不是 Exceptions。通过这种方式,您在开发期间引入了您所追求的保护,但是在生产中(假设是 Release 构建),断言没有被编译,并且每次进行此调用时都不会导致(轻微)性能损失;

Debug.Assert(Assembly.GetCallingAssembly().FullName.Contains("DynamoDB"), "Invalid constructor usage");
于 2012-05-29T22:59:53.950 回答
1

使用 PostSharp,您可以使用架构约束来验证未从用户代码调用某些构造函数(执行 ReferentialConstraint 并将约束附加到类,可能使用多播和继承)。基本上,如果从反射中唯一合法地使用此代码,则如果您发现对构造函数的任何引用,则可能会发出错误,期望来自其他构造函数的链接。

请注意,这不会阻止从构造调用new T()构造函数,其中 T 是泛型类型参数。所以只禁止新的运算符:从您的引用方面,使用 ReflectionSearch.GetMethodsUsingDeclaration 并过滤(Instructions & MethodUsageInstructions.NewObject) != 0.

编辑:添加了有关 ReflectionSearch.GetMethodsUsingDeclaration 和 MethodUsageInstructions 的详细信息。

于 2012-05-30T08:56:10.683 回答