OP 请仔细阅读XY Problem,我强烈怀疑您的问题有比您在此处要求的更好的解决方案。
类型继承
实现这一点的一种方法是通过继承,但这实际上与您期望的相反,c# 中的 child 类型无法删除 parent 类型,所以在这个解决方案中,我们将ClientModel 设为孩子!
- 将您当前的班级重命名为
ClientModelBase
- 添加一个名为
ClientModel 的新类,它继承自ClientModelBase
- 将电子邮件属性从
ClientModelBase 移动到ClientModel
结果如下:
public class ClientModelBase
{
[Required]
public int Id { get; set; }
[Required]
[MinLength(2, ErrorMessage = "First name can not be shorter than 2 characters")]
public string FirstName { get; set; }
[Required]
[MinLength(2, ErrorMessage = "Last name can not be shorter than 2 characters")]
public string LastName { get; set; }
}
public class ClientModel : ClientModelBase
{
public string Email { get; set; }
}
现在在运行时,您可以将ClientModel 的实例转换为ClientModelBase,因此对于需要ClientModel 没有 Email 属性的方法,您可以将参数类型设置为@ 987654334@.
// Get an instance of a client
ClientModel client = clientRepo.ByKey(123);
ProcessClientWithoutEmail(client);
...
public void ProcessClientWithoutEmail(ClientModelBase client)
{
// client doesn't expose an Email property
}
这种隐式转换技术类似于C# value boxing,如果您稍后在逻辑链中需要它,Email 属性在技术上仍然可以访问,我们已经有效地对对象应用了掩码,以便编译器仅将其视为基础键入,何时或如果需要,并且只有当原始实例是 ClientModel,您才能将引用转换回具有 Email 属性的 ClientModel。
接口[组成]
您也可以使用interface,而不是创建一个基类 供ClientModel 继承。然而,这需要更多的代码来实现,因为您需要完全定义接口的原型。最终结果是相似的,它对原始模型的影响较小,因为唯一的变化是声明 ClientMode 实现新的IClientModelName 接口:
public class ClientModel : IClientModelName
{
[Required]
public int Id { get; set; }
[Required]
[MinLength(2, ErrorMessage = "First name can not be shorter than 2 characters")]
public string FirstName { get; set; }
[Required]
[MinLength(2, ErrorMessage = "Last name can not be shorter than 2 characters")]
public string LastName { get; set; }
public string Email { get; set; }
}
public interface IClientModelName
{
int Id { get; set; }
string FirstName { get; set; }
string LastName { get; set; }
}
这与前面的代码示例几乎相同,但有一个重要区别,虽然仍然可以转换回 ClientModel,但我们现在可以传递与 ClientModel 来自的 repo 无关的对象,所以这简化了单元测试或模拟。
如果您的生产代码已经具有复杂的继承或其他影响初始化的因素,您可能会发现使用接口的基于组合的解决方案更适合您的用例。
// Get an instance of a client
ClientModel client = clientRepo.ByKey(123);
ProcessClientWithoutEmail(client);
...
public void ProcessClientWithoutEmail(IClientModelName client)
{
// client doesn't expose an Email property
}