我的域程序集中有一个不可变的Customer类。它包含以下GET属性:id,firstname和lastname。我的持久性程序集中有一个CustomerRepository类。反过来,此CustomerRepository类应使用远程web-serivce填充并返回Customer对象。
我的Customer类不包含setter属性,它包含一个私有构造函数。原因 - 我不希望UI开发人员得到错误的想法 - 他不应该能够创建或更改Customer对象。
我的问题:如何让我的CustomerRepository填充我的Customer对象。反射?或者我应该牺牲我的设计并启用公共构造函数来构建客户对象?
答案 0 :(得分:3)
我同情减少API表面的愿望而不是误导来电者,但我仍然建议添加一个公共构造函数。事实上,没有setter,也没有公共SaveCustomer
方法,这一点应该足以说明客户是不可变的。
如果你真的不想要一个公共构造函数,请考虑你是否真的需要单独的域和持久性程序集:有充分的理由将相关代码拆分成两个程序集,但它不应该是默认位置,不应该将名称空间替换为组织代码的主要方式(Patrick Smacchia撰写了a few great articles explaining why)。
如果将它们组合成一个程序集,则可以将构造函数设置为内部并完成它。 (正如另一位受访者提到的,InternalsVisibleTo是一个可行的替代方案 - 但它实际上只是一个黑客攻击:你的类和设计目标告诉你这些应该在一个程序集中。)
答案 1 :(得分:2)
您可能希望声明一个internal
构造函数,并将三个属性作为参数。如果您的CustomerRepository
与Customer
课程不在同一个程序集中,那么您可以使用以下属性显示internal
:
[assembly: InternalsVisibleTo ("CustomerAssembly, PublicKey=...")]
在Customer
程序集中。
编辑:顺便说一下,如果你需要创建大量的对象,我不建议使用反射,因为这样做会比直接调用构造函数慢几个数量级。如果你真的必须走这条路线,我建议你添加一个静态工厂方法,你可以通过反射调用它来获得一个有效的分配器。
例如:
class Customer
{
private Customer(...) { ... }
private static ICustomerFactory GetCustomerFactory()
{
return new CustomerFactory();
}
private class CustomerFactory : ICustomerFactory
{
Customer CreateCustomer(...) { return new Customer(...); }
}
}
public interface ICustomerFactory
{
Customer CreateCustomer(...);
}
使用反射来调用Customer.GetCustomerFactory
,从那时起,您将有一种快速有效的方法来创建Customer
。