【发布时间】:2017-06-06 09:40:15
【问题描述】:
想象一下 Xamarin 解决方案中的以下场景:
组件 A (PCL):
public abstract class MyBaseClass
{
public MyBaseClass()
{
[...]
}
[...]
}
程序集 B(第 3 方库):
public class SomeLibClass
{
[...]
public void MethodThatCreatesClass(Type classType){
[...]
//I want to allow this to work
var obj = Activator.CreateInstance(classType);
[...]
}
[...]
}
程序集 C(主项目):
public class ClassImplA:MyBaseClass{
[...]
}
public class ClassImplA:MyBaseClass{
[...]
}
public class TheProblem{
public void AnExample(){
[...]
//I want to block these instantiations for this Assembly and any other with subclasses of MyBaseClass
var obj1 = new ClassImplA()
var obj2 = new ClassImplB()
[...]
}
}
如何防止子类在它们自己的程序集中被实例化并只允许它们在超类和第三方库上(使用Activator.CreateInstance)?
尝试 1
虽然我可以使用internal constructor 创建基类,但后来我发现这是多么愚蠢,因为子类无法继承构造函数,因此它们无法从超类继承.
尝试 2
我尝试在基类上使用Assembly.GetCallingAssembly,但这在 PCL 项目中不可用。我找到的解决方案是通过反射调用它,但它也不起作用,因为这两种情况下基类的结果都是Assembly C(我认为这是因为谁调用MyBaseClass的构造函数是确实是ClassImplA 和ClassImplB 两种情况的默认构造函数。
关于如何做到这一点的任何其他想法?还是我在这里遗漏了什么?
更新
这个想法是让 PCL 程序集从离线同步中抽象出主项目(和其他一些项目)。
鉴于此,我的 PCL 使用自己的数据库进行缓存,而我想要为数据库的每条记录仅提供一个实例(这样当属性更改时,所有分配的变量都将具有该值,我可以确保因为主项目中没有人能够创建这些类,并且它们将由一个处理单个实例的 manager class 提供给变量。
由于我为此使用SQLite-net,并且因为它要求每个实例都有一个空构造函数,我需要一种方法来仅允许创建 SQLite 和 PCL 程序集在主项目程序集上声明的那些子类
更新 2
如果可以使用 Reflection 绕过此问题的解决方案,我没有问题,因为我的主要重点是防止人们在主项目上犯一个简单的错误new ClassImplA。但是,如果可能的话,我希望拥有这样的东西,这样JsonConvert.DeserializeObject<ClassImplA> 这样的东西实际上会因异常而失败。
【问题讨论】:
-
通过一些限制,您可以使构造函数在内部受到保护,并使第 3 方组装成为朋友。但是......如果他们明确检查公共默认 ctor,那么这将失败。如果派生类显式声明了一个公共默认 ctor,那么它就会失败。如果他们用反射覆盖了你所有的安全检查,那么它就会失败......
-
@AdrianoRepetti 请查看我关于 Reflection 案例的更新。关于
protected internal,子类可以使用它吗?因为 afaik,base()对他们来说是不可用的,因为它对主项目程序集不可见,对吧? -
Protected 将使其对子类和内部朋友程序集可见。老实说,我不确定 Activator.CreateInstance 将如何管理它。
-
@AdrianoRepetti 我只是尝试将
MyBaseClass的构造函数更改为protected internal,但这仍然允许我在它们自己的程序集中实例化子类。我错过了什么?作为记录,子类将不受我控制,在我的示例测试用例中,它们没有声明构造函数(这使它们使用默认构造函数)
标签: c# inheritance subclass .net-assembly instantiation